The reason the stream engine can't easily decide to bypass streams
is that there can be non-stream dependent rules that wouldn't match
if bypassing is done too aggressively.
However, if there is no detection engine, there is no reason to hold
back. In this case we can bypass as soon as the stream engine is done
with a session.
This patch turn on code optimization on BPF filter building by
libpcap. This allow to reduce the size of the BPF bytecode and
thus increase the size of BPF filter supported by Suricata.
Reported-by: Martijn van Oosterhout
Rules can contain conflicting statements and lead to a unmatchable rule.
2 examples are rejected by this patch:
1. dsize < content
2. dsize < content@offset
Bug #2187
GCC7 said:
CC util-radix-tree.o
In file included from util-debug-filters.h:29:0,
from util-debug.h:34,
from suricata-common.h:421,
from util-radix-tree.c:26:
util-radix-tree.c: In function ‘SCRadixAddKey’:
util-mem.h:177:12: error: argument 1 range [18446744071562067968, 18446744073709551615] exceeds maximum object size 9223372036854775807 [-Werror=alloc-size-larger-than=]
ptrmem = malloc((a)); \
~~~~~~~^~~~~~~~~~~~~
util-radix-tree.c:749:42: note: in expansion of macro ‘SCMalloc’
if ( (inter_node->netmasks = SCMalloc((node->netmask_cnt - i) *
^~~~~~~~
In file included from suricata-common.h:69:0,
from util-radix-tree.c:26:
/usr/include/stdlib.h:443:14: note: in a call to allocation function ‘malloc’ declared here
extern void *malloc (size_t __size) __THROW __attribute_malloc__ __wur;
^~~~~~
scan-build said:
util-radix-tree.c:749:42: warning: Call to 'malloc' has an allocation size of 0 bytes
if ( (inter_node->netmasks = SCMalloc((node->netmask_cnt - i) *
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./util-mem.h:177:14: note: expanded from macro 'SCMalloc'
ptrmem = malloc((a)); \
^~~~~~~~~~~
1 warning generated.
Example:
util-runmodes.c: In function ‘RunModeSetIPSAutoFp’:
util-runmodes.c:496:40: error: ‘snprintf’ output may be truncated before the last format character [-Werror=format-truncation=]
snprintf(qname, sizeof(qname), "pickup%d", thread+1);
^~~~~~~~~~
util-runmodes.c:496:9: note: ‘snprintf’ output between 8 and 17 bytes into a destination of size16
snprintf(qname, sizeof(qname), "pickup%d", thread+1);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Solved by reducing 'thread' to a uint16_t and limiting the max
thread count to 1024.
The http_host keyword checks if the regex contains uppercase characters.
This check was rejecting valid syntax in the following format:
content:"|2E|suricata"; http_host; pcre:"/\x2Esuricata$/W";
This patch addresses this case.
Bug #1957.
The application log is subject to rotation, so the check for
rotation, the actual rotation and write needs to be done under
lock to ensure the file pointer is in a consisten state
at the time of write().
Fixes issue:
https://redmine.openinfosecfoundation.org/issues/2155
On OpenBSD 6.0 and 6.1 the following pcap gets a datalink type of
101 instead of our defined DLT_RAW.
File type: Wireshark/tcpdump/... - pcap
File encapsulation: Raw IP
File timestamp precision: microseconds (6)
Packet size limit: file hdr: 262144 bytes
Number of packets: 23
File size: 11 kB
Data size: 11 kB
Capture duration: 7,424945 seconds
First packet time: 2017-05-25 21:59:31,957953
Last packet time: 2017-05-25 21:59:39,382898
Data byte rate: 1536 bytes/s
Data bit rate: 12 kbps
Average packet size: 496,00 bytes
Average packet rate: 3 packets/s
SHA1: 120cff9878b93ac74b68fb9216027bef3b3c018f
RIPEMD160: 35fa287bf30d8be8b8654abfe26e8d3883262e8e
MD5: 13fe4bc50fe09bdd38f07739bd1ff0f0
Strict time order: True
Number of interfaces in file: 1
Interface #0 info:
Encapsulation = Raw IP (7/101 - rawip)
Capture length = 262144
Time precision = microseconds (6)
Time ticks per second = 1000000
Number of stat entries = 0
Number of packets = 23
On Linux it is 12.
On the tcpdump/libpcap site the DLT_RAW is defined as 101:
http://www.tcpdump.org/linktypes.html
Strangely, on OpenBSD the DLT_RAW macro is defined as 14 as expected.
So for some reason, libpcap on OpenBSD uses 101 which seems to match
the tcpdump/libpcap documentation.
So this patch adds support for datalink 101 as RAW.
Certain rules can apply to both TCP and UDP. For example 'alert dns'
rules are inspected against both TCP and UDP. This lead to the
stream inspect engine being called on a UDP packet.
This patch fixes the issue by exiting early from the stream inspect
engine if a) proto is not TCP or b) ssn is not available
Bug #2158.
Clean up option parsing. Allow options to be disabled as well as
enabled.
E.g.
metadata: true
flow: false
The metadata setting will enable all. Then flow is disabled.
This patch adds a partial flow entry in the alert event
(if applayer or flow is selected) or simply app_proto if
it is not.
app_proto is useful as filter and aggregation field. And
the partial flow entry contains more information about the
proto as well as some volumetry info.
Observed:
STARTTLS creates 2 pseudo packets which are tied to a real packet.
TPR (tunnel packet ref) counter increased to 2.
Pseudo 1: goes through 'verdict', increments 'ready to verdict' to 1.
Packet pool return code frees this packet and decrements TPR in root
to 1. RTV counter not changed. So both are now 1.
Pseudo 2: verdict code sees RTV == TPR, so verdict is set based on
pseudo packet. This is too soon. Packet pool return code frees this
packet and decrements TPR in root to 0.
Real packet: TRP is 0 so set verdict on this packet. As verdict was
already set, NFQ reports an issue.
The decrementing of TPR doesn't seem to make sense as RTV is not
updated.
Solution:
This patch refactors the ref count and verdict count logic. The beef
is now handled in the generic function TmqhOutputPacketpool(). NFQ
and IPFW call a utility function VerdictTunnelPacket to see if they
need to verdict a packet.
Remove some unused macro's for managing these counters.
Since the parser now also does nfs2, the name nfs3 became confusing.
As it's still in beta, we can rename so this patch renames all 'nfs3'
logic to simply 'nfs'.
In normal records it will try to continue parsing.
GAP 'data' will be passed to file api as '0's. New call is used
so that the file API does know it is dealing with a GAP. Such
files are flagged as truncated at the end of the file and no
checksums are calculated.
TCP reassembly is now deactivated more frequently and triggering a
bypass on it is resulting in missing some alerts due forgetting
about packet based signature.
So this patch is introducing a dedicated flag that can be set in
the app layer and transmitted in the streaming to trigger bypass.
It is currently used by the SSL app layer to trigger bypass when
the stream becomes encrypted.
Only the tests that make sense were copied over, those testing
correlation of responses to requests were not.
Also, remove compiler warning when not built with
unit tests.
IDMEF alert contains two entities named Source and Target that are
defined using common language:
* "The Source class contains information about the possible source(s) of
the event(s) that generated an alert."
* "The Target class contains information about the possible target(s) of
the event(s) that generated an alert."
Previous alerts event were not following that so we can updated the code
when we know the direction thanks to the metadata field.
Use metadata provided information to output the Source and Target
in the definition of IDMEF.
The output is now the following:
"alert": {
"action": "allowed",
"gid": 1,
"signature_id": 1,
"rev": 1,
"signature": "connection to home",
"category": "",
"severity": 3,
"source": {
"ip": "2001:31d0:000a:f68a:0000:0000:0000:0001",
"port": 80
},
"target": {
"ip": "2a01:0e34:ee97:b130:c685:08ff:dab3:c9c8",
"port": 48390
}
The target keyword allows rules writer to specify information about
target of the attack. Using this keyword in a signature causes
some fields to be added in the EVE output. It also fixes ambiguity
in the Prelude output.
Suricata was inconditionaly dropping packets that are invalid with
respect to the streaming engine. In some corner case like asymetric
trafic capture, this was leading to dropping some legitimate trafic.
The async-oneside option did help but this was not perfect in some
real life case. So this patch introduces an option that allow the
user to tell Suricata not to drop packet that are invalid with
respect to streaming.
Current file storing approach is using a open file, write data,
close file logic. If this technic is fixing the problem of getting
too much open files in Suricata it is not optimal.
Test on a loop shows that open, write, close on a single file is
two time slower than a single open, loop of write, close.
This patch updates the logic by storing the fd in the File structure.
This is done for a certain number of files. If this amount is exceeded
then the previous logic is used.
This patch also adds two counters. First is the number of
currently open files. The second one is the number of time
the open, write, close sequence has been used due to too much
open files.
In EVE, the entries are:
stats {file_store: {"open_files_max_hit":0,"open_files":5}}
Wrapper around Suricata's File and FileContainer API. Built around
assumption that a rust owned structure will have a
'SuricataFileContainer' member that is managed by the C-side of
things.
Where the context is a struct passed from C with pointers
to all the functions that may be called.
Instead of referencing C functions directly, wrap them
in function pointers so pure Rust unit tests can still run.
Rust is currently optional, use the --enable-rust configure
argument to enable Rust.
By default Rust will be built in release mode. If debug is enabled
then it will be built in debug mode.
On make dist, "cargo vendor" will be run to make a local copy
of Rust dependencies for the distribution archive file.
Add autoconf checks to test for the vendored source, and if it
exists setup the build to use the vendored code instead of
fetching it from the network.
Also, as Cargo requires semantic versioning, the Suricata version
had to change from 4.0dev to 4.0.0-dev.
A parser can now set a flag that will tell the application
layer that it is capable of handling gaps. If enabled, and a
gap occurs, the app-layer needs to be prepared to accept
input that is NULL with a length, where the length is the
number of bytes lost. It is up to the app-layer to
determine if it can sync up with the input data again.
Initialize midstream with async if enabled. Unset async on seeing
bidirectional traffic.
If only async-oneside is enabled, set ASYNC flag on session creation
when receiving a SYN packet.
Let last_ack stay in sync with next_seq so that various checks work
better.
For logging streaming TCP data so far the individual segments where
used. However since the last big stream changes, the segments are
no longer the proper place for this. Segments can now have overlaps
etc.
This patch introduces a new tracker. Next to the existing 'app' and
'raw' trackers, the new tracker is 'log'. When the TCP logging is
used, a flag in the config is set and the log tracker is used to
determine how much of the stream window can be moved.
Call SCStreamingBuffer as follows:
data, sb_open, sb_close, sb_ts, sb_tc = SCStreamingBuffer()
sb_ts and sb_tc are bools indicating the direction of the data.
Improve output of unix mode in --list-runmodes
Honor the runmode commandline setting. Supported are 'single'
and 'autofp', with the latter still the default.
Move all GAP checks into CheckGap. Remove seg_list based check.
Also remove seg_list == NULL check to make sure the Gap check is
done on an empty list as well.
Improve next_seq < last_ack check, but add data beyond gap check.
When looping available files 'flags' misuse would lead to all files
being closed after the first close.
This patch separates per file and per call flags.
Some protocols transfer multiple files in parallel. To support this add
a 'track id' to the API. This track id is set by the protocol parser. It
will use this id to indicate what file in the FileContainer it wants to
act on.
Change SCFlowAppLayerProto to return 5 values:
<alproto> <alproto_ts> <alproto_tc> <alproto_orig> <alproto_expect>:
alproto: detected protocol
alproto_ts: detected protocol in toserver direction
alproto_tc: detected protocol in toclient direction
alproto_orig: pre-change/upgrade protocol
alproto_expected: expected protocol in change/upgrade
Orig and expect are used when changing and upgrading protocols. In a
SMTP STARTTLS case, orig would normally be set to "smtp" and expect
to "tls".
When switching protocol from http to tls the following corner case
was observed:
pkt 6, TC "200 connection established"
pkt 7, TS acks pkt 6 + adds "client hello"
pkt 8 TC, acks pkt 7
pkt 8 is where normally the detect on the 200 connection established
would run however before detection runs the app-layer is called
and it resets the state
So the issue is missed detection on the last data in the original
protocol before the switch.
Another case was:
TS -> STARTTLS
TC -> Ack "STARTTLS data"
220
TS -> Ack "220 data"
Client Hello
In IDS mode, this made a rule that wanted to look at content:"STARTTLS"
in combination with the protocol SMTP 'alert smtp ... content:"STARTTLS";'
impossible. By the time the content would match, the protocol was already
switched.
This patch fixes this case by creating a 'Detect/Log Flush' packet in
both directions. This will force final inspection and logging of the
pre-upgrade protocol (SMTP in this example) before doing the final
switch.
Add API calls to upgrade to TLS or to request a protocol change
without a specific protocol expectation.
If the HTTP CONNECT session includes a port on the url, use that to
look up the probing parser during protocol detection. Solves a
missed detection of a SSLv2 session that upgrades to TLSv1. SSLv2
relies on the probing parser which is limited to certain ports.
In case of STARTTLS in SMTP and FTP, the port is hardcoded to 443.
A new event APPLAYER_UNEXPECTED_PROTOCOL is set if there was a
mismatch.
Support changing the application level protocol for a flow. This is
needed by STARTTLS and HTTP CONNECT to switch from the original
alproto to tls.
This commit allows a flag to be set 'FLOW_CHANGE_PROTO', which
triggers a new protocol detection on the next packet for a flow.
Set flags by default:
-Wmissing-prototypes
-Wmissing-declarations
-Wstrict-prototypes
-Wwrite-strings
-Wcast-align
-Wbad-function-cast
-Wformat-security
-Wno-format-nonliteral
-Wmissing-format-attribute
-funsigned-char
Fix minor compiler warnings for these new flags on gcc and clang.
In preparation of turning input to keyword parsers to const add
options to the common rule parser to enforce and strip double
quotes and parse negation support.
At registration, the keyword can register 3 extra flags:
SIGMATCH_QUOTES_MANDATORY: value to keyword must be quoted
SIGMATCH_QUOTES_OPTIONAL: value to keyword may be quoted
SIGMATCH_HANDLE_NEGATION: leading ! is parsed
In all cases leading spaces are removed. If the 'quote' flags are
set, the quotes are removed from the input as well.
The expression 'isdataat:!1,relative' is used to make sure a match
is at the end of a buffer quite often. This patch optimizes this case
for 'content' followed by the expression. It enforces it by setting
and 'ends with' flag on the content and then taking that flag into
account while doing the pattern match.
Content inspection optimization: when just distance is used without
within we don't need to search recursively.
E.g. content:"a"; content:"b"; distance:1; will scan the buffer for
'a' and when it finds 'a' it will scan the remainder for 'b'. Until
now, the failure to find 'b' would lead to looking for the next 'a'
and then for 'b' after that. However, we already inspected the
entire buffer for 'b', so we know this will fail.
Now that MPM runs when the TX progress is right, stateful detection
operates differently.
Changes:
1. raw stream inspection is now also an inspect engine
Since this engine doesn't take the transactions into account, it
could potentially run multiple times on the same data. To avoid
this, basic result caching is in place.
2. the engines are sorted by progress, but the 'MPM' engine is first
even if the progress is higher
If MPM flags a rule to be inspected, the inspect engine for that
buffer runs first. If this step fails, the rule is no longer
evaluated. No state is stored.
Previously the MPM/Prefilter engines would suggest the same rule
candidates multiple times.
For example, while processing the request body, the http headers
would be inspected by MPM multiple times.
The mask check was one way to quickly decide which rules could be
skipped.
Now that the MPM engines normally return a rule just once, this
mask check no longer makes sense. If the rule meets the ip/port/
direction based conditions, it needs to be evaluated if the MPM
said so. Even if not all conditions are yet true.
WIP disable mask as it no longer makes sense
WIP redo mask match
In various scenarios buffers would be checked my MPM more than
once. This was because the buffers would be inspected for a
certain progress value or higher.
For example, for each packet in a file upload, the engine would
not just rerun the 'http client body' MPM on the new data, it
would also rerun the method, uri, headers, cookie, etc MPMs.
This was obviously inefficent, so this patch changes the logic.
The patch only runs the MPM engines when the progress is exactly
the intended progress. If the progress is beyond the desired
value, it is run once. A tracker is added to the app layer API,
where the completed MPMs are tracked.
Implemented for HTTP, TLS and SSH.
Instead of killing all reassembly instantly do things slightly more
gracefully:
1. disable app-layer reassembly immediately
2. flag raw reassembly not to accept new data
This will allow the current data to be inspected still.
After detect as run the raw reassembly will be fully disabled and
thus all reassembly will be as well.
If raw reassembly falls behind, for example because no raw mpm is
active, then we need to sync up to the app progress if that is
available, or to the generic tcp tracking otherwise.
Now that detect moves the raw progress forward, it's important
to deal with the case where detect don't consider raw inspection.
If no 'stream' rules are active, disable raw. For this the disable
raw flag is now per stream.
Implement the inline mode for raw content inspection. Packets
are leading, and when a packet's payload has been added to the
stream, the packet is inspected in the context of the stream.
Reassembly will return a buffer with the packet data with older
data in front of it and after it, if available.
At flow timeout, we no longer need to first run reassembly in
one dir, then inspection in the other. We can do both in single
packet now.
Disable pseudo packets when receiving stream end packets. Instead
call the app-layer parser in the packet direction for stream end
packets and flow end packets.
These changes in handling of those stream end packets make the
pseudo packets unnecessary.
Remove the 'StreamMsg' approach from the engine. In this approach the
stream engine would create a list of chunks for inspection by the
detection engine. There were several issues:
1. the messages had a fixed size, so blocks of data bigger than ~4k
would be cut into multiple messages
2. it lead to lots of data copying and unnecessary memory use
3. the StreamMsgs used a central pool
The Stream engine switched over to the streaming buffer API, which
means that the reassembled data is always available. This made the
StreamMsg approach even clunkier.
The new approach exposes the streaming buffer data to the detection
engine. It has to pay attention to an important issue though: packet
loss. The data may have gaps. The streaming buffer API tracks the
blocks of continuous data.
To access the data for inspection a callback approach is used. The
'StreamReassembleRaw' function is called with a callback and data.
This way it runs the MPM and individual rule inspection code. At
the end of each detection run the stream engine is notified that it
can move forward it's 'progress'.
Make stream engine use the streaming buffer API for it's data storage.
This means that the data is stored in a single reassembled sliding
buffer. The subleties of the reassembly, e.g. overlap handling, are
taken care of at segment insertion.
The TcpSegments now have a StreamingBufferSegment that contains an
offset and a length. Using this the segment data can be retrieved
per segment.
Redo segment insertion. The insertion code is moved to it's own file
and is simplified a lot.
A major difference with the previous implementation is that the segment
list now contains overlapping segments if the traffic is that way.
Previously there could be more and smaller segments in the memory list
than what was seen on the wire.
Due to the matching of in memory segments and on the wire segments,
the overlap with different data detection (potential mots attacks)
is much more accurate.
Raw and App reassembly progress is no longer tracked per segment using
flags, but there is now a progress tracker in the TcpStream for each.
When pruning we make sure we don't slide beyond in-use segments. When
both app-layer and raw inspection are beyond the start of the segment
list, the segments might not be freed even though the data in the
streaming buffer is already gone. This is caused by the 'in-use' status
that the segments can implicitly have. This patch accounts for that
when calculating the 'left_edge' of the streaming window.
Raw reassembly still sets up 'StreamMsg' objects for content
inspection. They are set up based on either the full StreamingBuffer,
or based on the StreamingBufferBlocks if there are gaps in the data.
Reworked 'stream needs work' logic. When a flow times out the flow
engine checks whether a TCP flow still needs work. The
StreamNeedsReassembly function is used to test if a stream still has
unreassembled segments or uninspected stream chunks.
This patch updates the function to consider the app and/or raw
progress. It also cleans the function up and adds more meaningful
debug messages. Finally it makes it non-inline.
Unittests have been overhauled, and partly moved into their own files.
Remove lots of dead code.
Add list of 'blocks'. This list contains offsets and lengths to
continuous data blocks. This is useful for TCP tracking where we
can have data gaps.
The blocks don't contain any data themselves, instead they contain
lenght and offsets. This way no extra copying is needed.
On inserting new data, existing blocks are expanded instead of
having multiple neighbouring blocks.
Implement common code to easily add more per HTTP header detection
keywords.
Implement http_accept sticky buffer. It operates on the HTTP Accept
header.
We assume session resumption has occurred if the Client Hello message
included a session id, we have not seen the server certificate, but
we have seen a Change Cipher Spec message from the server.
Previously, these transactions were not logged at all because the
server cert was never seen.
Ticket: https://redmine.openinfosecfoundation.org/issues/1969
eve: detects libevent for async redis at configure
eve: moves redis output code to new file - util-log-redis.{c,h}
eve: redis ECHO and QUIT commands for async mode
eve: redis output defaults if conf is missing
If running against a pcap there is no reason to drop events,
a blocking socket is fine here. So only do non-blocking writes
when running off a live device.
Writing to a unix socket can cause Suricata to block in the
packet path. This could happen if the read-endpoint of the
unix socket stays connected, but stops reading, or simply
can't read fast enough as part of its event processing.
To choose packets over events, do non-blocking socket
writes and drop the event if the write would block and
update a dropped counter.
Recursively create new log directories when needed. This makes it
possible to use date modifiers in the file path to create
directories based on date, e.g.:
/var/log/suricata/2017/02/14/
Rotate log file based on time. Support both rotating based on a timer (XXs,
XXm, XXd, XXw) and rotating based on a absolute time, like each minute,
hour or day.
If a subsequent fragment has a lower offset than a previous
one and overlaps, trim off the beginning of the previous
fragment.
Based on an issue reported privately.
UnixManagerThreadInit needs to return a failure code if the socket
fails to initialize to avoid entering the UnixManager loop which
will continuously fail on the call to bind, as no listening
socket was setup.
This can occur when the socket fails to initialize due to a
permissions error and fatal init errors is not on.
app-layer-modbus.c:1226:39: warning: taking address of packed member 'transactionId' of class or structure 'ModbusHeader_' may result in an unaligned pointer value [-Waddress-of-packed-member]
if (ModbusExtractUint16(modbus, &(header->transactionId), input, input_len, &offset) ||
^~~~~~~~~~~~~~~~~~~~~
app-layer-modbus.c:1228:39: warning: taking address of packed member 'protocolId' of class or structure 'ModbusHeader_' may result in an unaligned pointer value [-Waddress-of-packed-member]
ModbusExtractUint16(modbus, &(header->protocolId), input, input_len, &offset) ||
^~~~~~~~~~~~~~~~~~
app-layer-modbus.c:1230:39: warning: taking address of packed member 'length' of class or structure 'ModbusHeader_' may result in an unaligned pointer value [-Waddress-of-packed-member]
ModbusExtractUint16(modbus, &(header->length), input, input_len, &offset) ||
^~~~~~~~~~~~~~
3 warnings generated.
Bug #2088
clang-4.0 reported:
util-pool.c:242:13: warning: logical not is only applied to the left hand side of this bitwise operator [-Wlogical-not-parentheses]
if (! pb->flags & POOL_BUCKET_PREALLOCATED) {
^ ~
util-pool.c:242:13: note: add parentheses after the '!' to evaluate the bitwise operator first
if (! pb->flags & POOL_BUCKET_PREALLOCATED) {
^
( )
util-pool.c:242:13: note: add parentheses around left hand side expression to silence this warning
if (! pb->flags & POOL_BUCKET_PREALLOCATED) {
^
( )
util-pool.c:261:13: warning: logical not is only applied to the left hand side of this bitwise operator [-Wlogical-not-parentheses]
if (! pb->flags & POOL_BUCKET_PREALLOCATED) {
^ ~
util-pool.c:261:13: note: add parentheses after the '!' to evaluate the bitwise operator first
if (! pb->flags & POOL_BUCKET_PREALLOCATED) {
^
( )
util-pool.c:261:13: note: add parentheses around left hand side expression to silence this warning
if (! pb->flags & POOL_BUCKET_PREALLOCATED) {
^
( )
2 warnings generated.
In some cases, observed with inspect limits 0, the body tracking could
get confused. When all chunks were already freed, a new chunk would
be considered to be the start of the body. This would overwrite the
bodies 'content_len_so_far' tracker, instead of adding to it. This in
turn could lead to a assertion abort in the inspection code.
This patch redoes the append code to always add the current lenght. It
cleans up the code to remove redundant logic.
Issue: https://redmine.openinfosecfoundation.org/issues/2078
Reported-By: Jørgen Bøhnsdalen
"p" was being used in the macro but was not an argument to
the macro, but it worked due to the context of the macro.
Use the actual macro argument, d2, instead of p.
Results in no change to generated code.
Add SCFlowTimestamps() to return startts and lastts as seconds and
microseconds from flow.
Examples:
startts, lastts = SCFlowTimestamps()
startts_s, lastts_s, startts_us, lastts_us = SCFlowTimestamps()
Issue:
https://redmine.openinfosecfoundation.org/issues/2041
One approach to fixing this issue to just validate the
checksum instead of regenerating it and comparing it. This
method is used in some kernels and other network tools.
When validating, the current checksum is passed in as an
initial argument which will cause the final checksum to be 0
if OK. If generating a checksum, 0 is passed and the result
is the generated checksum.
When detection is running flags are set on flows to indicate if file
hashing is needed. This is based on global output settings and rules.
In the case of --disable-detection this was not happening, so all
files where hashed with all methods. This has a significant
performance impact.
This patch adds logic to set the flow flags in --disable-detect mode.
When bytejump was told to convert some payload data to int from a
string it would print an error to the screen if the conversion
failed. This is unwanted as the payload is controlled by an attacker
and printing is expensive.
A GAP during protocol detection would lead to all reassembly
getting disabled, so also the raw reassembly. In addition, it
could prevent the opposing side from doing protocol detection.
This patch remove the 'disable reassembly' logic. Stream engine
will take the stream with GAP and app-layer will make the proto
detection as complete.
All loggers were wrapping just the write in a lock with some
updating a counter. This moves the lock into the write function.
The log_ctx alerts counter was also removed as many modules have
stopped using this and the alert count is available elsewhere.
Should satisfy Coverity CID 1400798:
CID 1400798 (#1 of 1): Data race condition (MISSING_LOCK) 2.
missing_lock: Accessing log_ctx->rotation_flag without holding lock
LogFileCtx_.fp_mutex. Elsewhere, "LogFileCtx_.rotation_flag" is accessed
with LogFileCtx_.fp_mutex held 4 out of 5 times.
Which appears to be a false positive as all calls to SCLogFileWrite
were done under lock, but this will make it more explicit.
Match on TLS certificate serial number using tls_cert_serial
keyword, e.g.:
alert tls any any -> any any (msg:"TLS cert serial test";
tls_cert_serial; content:"5C:19:B7:B1:32:3B:1C:A1";
sid:12345;)
Add function LuaGetCertSerial to print serial number from TLS
certificate.
Example:
function log (args)
serial = TlsGetCertSerial()
if serial then
file:write(serial .. "\n");
file:flush()
end
end
Give unified2 a nostamp option which will create the file
without the timestamp suffix (like Snort's nostamp option).
Also register for rotation notification on SIGHUP so the file
will be recreated if it is removed by an external rotation
program (only when nostamp is used).
Log src_ip, dst_ip and proto for root packet (p->root) if the
packet that triggered is inside a tunnel, as JSON object
'tunnel'. Also log recursion depth to indicate the depth of
the tunnel.
Move code to get 5-tuple in JSON object to own function 'JsonFiveTuple'.
This enables this code to be reused when printing 'parent' JSON object in
output-json-alert.
add-hostbit adds a named hostbit with an expire time in seconds.
remove-hostbit removes hostbit by name.
add-hostbit, remove-hostbit return success or failure.
list-hostbit returns a json array of hostbits with their name and
expire time:
{
"message": {
"count": 1,
"hostbits":
[{
"expire": 3222,
"name": "firefox-users"
}]
},
"return": "OK"
}
Until now the way to specify a var name in pcre substring capture
into pkt and flow vars was to use the pcre named substring support:
e.g. /(?P<pkt_somename>.*)/
This had 2 drawbacks:
1. limitations of the name. The name could be max 32 chars, only have
alphanumeric and the underscore characters. This imposed limitations
that are not present in flowbits/ints.
2. we didn't actually use the named substrings in pcre through the
API. We parsed the names separately. So putting the names in pcre
would actually be wasteful.
This patch introduces a new way of mapping captures with names:
pcre:"/(.*)/, pkt:somename";
pcre:"/([A-z]+) ([0-9]+)/, pkt:somename,flow:anothername";
The order of the captures and the order of the names are mapped 1 on 1.
This method is no longer limited by the pcre API's naming limits. The
'flow:' and 'pkt:' prefixes indicate what the type of variable is. It's
mandatory to specify one.
The old method is still supported as well.
Flowvars were already using a temporary store in the detect thread
ctx.
Use the same facility for pktvars. The reasons are:
1. packet is not always available, e.g. when running pcre on http
buffers.
2. setting of vars should be done post match. Until now it was also
possible that it is done on a partial match.
Until now variable names, such as flowbit names, were local to a detect
engine. This made sense as they were only ever used in that context.
For the purpose of logging these names, this needs a different approach.
The loggers live outside of the detect engine. Also, in the case of
reloads and multi-tenancy, there are even multiple detect engines, so
it would be even more tricky to access them from the outside.
This patch brings a new approach. A any time, there is a single active
hash table mapping the variable names and their id's. For multiple
tenants the table is shared between tenants.
The table is set up in a 'staging' area, where locking makes sure that
multiple loading threads don't mess things up. Then when the preparing
of a detection engine is ready, but before the detect threads are made
aware of the new detect engine, the active varname hash is swapped with
the staging instance.
For this to work, all the mappings from the 'current' or active mapping
are added to the staging table.
After the threads have reloaded and the new detection engine is active,
the old table can be freed.
For multi tenancy things are similar. The staging area is used for
setting up until the new detection engines / tenants are applied to
the system.
This patch also changes the variable 'id'/'idx' field to uint32_t. Due
to data structure padding and alignment, this should have no practical
drawback while allowing for a lot more vars.
Matches on the start of a HTTP request or response.
Uses a buffer constructed from the request line and normalized request
headers, including the Cookie header.
Or for the response side, it uses the response line plus the
normalized response headers, including the Set-Cookie header.
Both buffers are terminated by an extra \r\n.
A sticky buffer that allows content inspection on a contructed buffer
of HTTP header names. The buffer starts with \r\n, the names are
separated by \r\n and the end of the buffer contains an extra \r\n.
E.g. \r\nHost\r\nUser-Agent\r\n\r\n
The leading \r\n is to make sure one can match on a full name in all
cases.
Some keywords need a scratch space where they can do store the results
of expensive operations that remain valid for the time of a packets
journey through the detection engine.
An example is the reconstructed 'http_header' field, that is needed
in MPM, and then for each rule that manually inspects it. Storing this
data in the flow is a waste, and reconstructing multiple times on
demand as well.
This API allows for registering a keyword with an init and free function.
It it mean to be used an initialization time, when the keyword is
registered.
To replace the hardcoded SigMatch list id's, use this API to register
and query lists by name.
Also allow for registering descriptions and whether mpm is supported.
Registration is only allowed at startup.
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.
A high level proto like HTTP implies TCP. However this wasn't set
until after all the parsing was complete which means that keywords
couldn't test if the ipproto matched.
This patch populates the ipprotos right when the higher level proto
is parsed.
The IP protocol was not being used to match fragments with
their packets allowing a carefully constructed packet
with a different protocol to be matched, allowing re-assembly
to complete, creating a packet that would not be re-assembled
by the destination host.
Due to the use of AFL_LOOP and initialization/deinit outside of it,
part of the fuzzing relied on the global 'state' in flow and defrag.
Because of this crashes that were found could not be reproduced. The
saved crash input was only the last in the series.
This patch addresses that. It requires a new output directory 'dump'
where the packet fuzzers will store all their input. If the AFL_LOOP
fails the files will not be removed and this 'serie' can be read
again for reproducing the issue.
e.g.: AFL would work with:
--afl-decoder-ppp=@@
and after a crash is found the produced serie can be read with:
--afl-decoder-ppp-serie=1486656919-514163
The series have a timestamp as name and a suffix that controls the
order in which the files will be 'replayed' in Suricata.
The size of a memory buffer to be allocated was kept in a signed int
instead of a size_t, leading to an overflow when large lists of long
and diverse patterns cause the amount of AC states to blow up (>2GB).
Fixes Redmine issues #1827 and #1843.
Signed-off-by: Sascha Steinbiss <sascha@steinbiss.name>
The `ts_ecr' and `ts_val' struct fields are integer types, not
pointers. This leads GCC 6.3.0 to complain about comparisons to
NULL.
Signed-off-by: Sascha Steinbiss <sascha@steinbiss.name>
The code to get the rule group (sgh) would return the group for
IP proto 0 instead of nothing. This lead to certain types of rules
unintentionally matching (False Positive).
Since the packets weren't actually IP, the logged alert records
were missing the IP header.
Bug #2017.
When packet is coming from a real ethernet card, the kernel is
stripping the vlan header and delivering a modified packet so
we need to insert the VLAN header back before sending the packet
on the wire.
To do so, we pass an option to the raw socket to add a reserve
before the packet data. It will get Suricata some head room to
to move the ethernet addresses before there actual place and
and insert the VLAN header in the correct place.
We get VLAN info from the ring buffer as the call of AFPWrite is
always done in the release function so we still have access to the
memory.
The JSON logger had already been updated to handle
transactions without a response. Apply the same logic
to the older dns-log where a logger is registered
for each direction.
Fixes issue 2012.
If the app-layer-parsing has a very long content it exceeds the maximum
defined in "alproto_name". This adds a check for the too long content
before it will be passed to "strlcpy" and logs an error.
The new Hyperscan 4.4 API provides a function to check for SSSE3
presence at runtime. This allows us to fall back to non-Hyperscan
matchers on systems without SSSE3 even when the suricata executable
is built with Hyperscan support. Addresses Redmine issue #2010.
Signed-off-by: Sascha Steinbiss <sascha@steinbiss.name>
Tested-by: Arturo Borrero Gonzalez <arturo@debian.org>
If segments section in the yaml is ommitted (default) or when the
pool size is set to 'from_mtu', the size of the pool will be MTU
minus 40. If the MTU couldn't be determined, it's assumed to be
1500, so the segment size for the bool will be 1460.
At shutdown, all flows that still need work are handled by the flow
force reassembly logic. This means one or more flow end pseudo packets
are generated and pushed through the engine for final detection and
logging.
In some cases this would not work correctly. This was caused by the
flow timeout logic kicking in before all the 'live' packets were
processed. Before the flow timeout handling runs the receive threads
are disabled, however the engine did not wait for the in-flight
packets to be fully processed. In autofp mode, packets could still
be in the queue between receive thread(s) and flow worker(s).
This patch adds a new function that 'drains' all the packet threads
of any in-progress packets before moving on the flow timeout logic.
Bug #1946.
Add SCFlowHasAlerts() to check if a flow has alerts. Returns true
on alerts, false otherwise.
Example:
has_alerts = SCFlowHasAlerts()
if has_alerts then
-- do something
end
This patch introduces the FileDataSize and FileTrackedSize functions.
The first one is just a renaming of the initial FilSize function
whereas the other one is using the newly introduced size field as
value.
The file size returned by FileSize is invalid if file store is not
used so we introduce a new size field in File structure that is used
to store the size.
Code was failing on a NULL return value which can be returned
when there was nothing todo instead of an error. Instead
check the errbuf for a non-NULL value to determine error.
Prevents the case where the logged id is incremented if a newer
transaction is complete and an older one is still outstanding.
For example, dns request0, unsolicited dns response, dns response0
would result in the valid response0 never being logged.
Similarily this could happen for:
request0, request1, response1, response0
which would end up having request0, request1 and response1 logged,
but response0 would not be logged.
This patch fixes an issue with hash computation resulting in the
invalidity of at least one hash when at least two different hashes
functions were used.
Impact was setting as `force-hash: [md5, sha256]` not to be valid.
Also it could lead to false negative if too different hash functions
had to be used on a single file due to signatures.
Fix bug that causes Suricata to crash when the tls.store keyword is used.
*** Error in `/usr/bin/suricata': free(): invalid next size (fast):
0x00007fd4b4373180 ***
null: At condition templatejs != NULL, the value of templatejs must be
NULL.
dead_error_condition: The condition templatejs != NULL cannot be true.
113 if (templatejs != NULL) {
CID 1324964 (#1 of 1): Logically dead code (DEADCODE)
dead_error_line: Execution cannot reach this statement:
json_decref(templatejs);.
114 json_decref(templatejs);
115 }
CID 1374306 (#1 of 1): Dereference before null check (REVERSE_INULL)
check_after_deref: Null-checking dns_state suggests that it may be null,
but it has already been dereferenced on all paths leading to the check.
585 if (dns_state != NULL && f != NULL) {
586 dns_state->last_req = f->lastts;
587 }
CID 1374305 (#1 of 1): Dereference before null check (REVERSE_INULL)
check_after_deref: Null-checking dns_state suggests that it may be null,
but it has already been dereferenced on all paths leading to the check.
366 if (dns_state != NULL && f != NULL) {
367 dns_state->last_req = f->lastts;
368 }
CID 1374307 (#1 of 1): Dereference before null check (REVERSE_INULL)
check_after_deref: Null-checking dns_state suggests that it may be null,
but it has already been dereferenced on all paths leading to the check.
317 if (dns_state != NULL && f != NULL) {
318 dns_state->last_resp = f->lastts;
319 }
Regular expression was not matching some authorized setting like
"![1234, 1235]". This patch simplify the regexp to match on
possible character and let the port parsing code handle the
complete verification.
When BUG_ON is a wrapper for assert(), we risk getting rid of certain
code lines. Assert is a no-op when NDEBUG is defined.
This patch defines an alternate path for BUG_ON that exits after
printing an error.
Bug #2003.
There have been some ICMPv6 types missing within the DecodeICMPV6 that
are added by this commit and the code check is adjusted to always use
the DEFINE.
When registering a probing parser allow to_server and
to_client parsers to be registered. Previously the
probing parser may be called for both directions which
in some cases works OK, but in others can cause
the to_client side to be detected as failed.
RFC states that "Commands and replies are not case sensitive" and
patterns were registered to be case sensitive. So this patch fixes
a trivial evasion of SMTP signatures.
Tls packets may contain several records. This increase the number
of allowed records per packet from 30 to 255, and adds a new and
more informative decoder event when this limit is reached.
No extensions are allowed in <TLSv.1.2, so don't trigger SURICATA
TLS handshake invalid length decoder event when no extensions are
specified in CLIENT HELLO.
In HTTP detection registered patterns were upper case only. Since the
detection is based on both sides this would still work for sessions
where one of the talkers misbehaved. If both sides misbehave this
would fail however, so this patch introduces case insensive matching.
Some examples from wiki caused parsing errors.
For example, "[1:80,![2,4]]" was treated as a mistake.
Also fixed loop detection in variables declaration. For example,
'A: "HOME_NET, !$HOME_NET"' resulted in parsing error.
Gcc 4.6 will warning with -Wshadow for a local variable
named "index" as <strings.h> has a function named "index".
Newer versions of gcc handle this case.