From e94d4f1915abe8200bb8cebf9e27326103951dcd Mon Sep 17 00:00:00 2001 From: Juliana Fajardini Date: Tue, 5 Nov 2024 22:54:50 -0300 Subject: [PATCH] userguide: explain rule types and categorization Add documentation about the rule types introduced by 2696fda04168cb82. Add doc tags around code definitions that are referenced in the docs. Task #https://redmine.openinfosecfoundation.org/issues/7031 --- doc/userguide/configuration/suricata-yaml.rst | 2 + doc/userguide/rules/index.rst | 1 + .../intro/OverallAlgoHorizontal-20241127.png | Bin 0 -> 74874 bytes .../OverallAlgoHorizontal-20241127.drawio | 104 ++ doc/userguide/rules/rule-types.rst | 936 ++++++++++++++++++ libhtp/.github/workflows/builds.yml | 110 ++ src/detect-engine.c | 2 + src/detect.h | 2 + 8 files changed, 1157 insertions(+) create mode 100644 doc/userguide/rules/intro/OverallAlgoHorizontal-20241127.png create mode 100644 doc/userguide/rules/intro/RawFlowcharts/OverallAlgoHorizontal-20241127.drawio create mode 100644 doc/userguide/rules/rule-types.rst create mode 100644 libhtp/.github/workflows/builds.yml diff --git a/doc/userguide/configuration/suricata-yaml.rst b/doc/userguide/configuration/suricata-yaml.rst index b6488b09f197..6d5558d62e08 100644 --- a/doc/userguide/configuration/suricata-yaml.rst +++ b/doc/userguide/configuration/suricata-yaml.rst @@ -2577,6 +2577,8 @@ Engine analysis and profiling Suricata offers several ways of analyzing performance of rules and the engine itself. +.. _config:engine-analysis: + Engine-analysis ~~~~~~~~~~~~~~~ diff --git a/doc/userguide/rules/index.rst b/doc/userguide/rules/index.rst index c8b586fecaa7..c9b48041d9e8 100644 --- a/doc/userguide/rules/index.rst +++ b/doc/userguide/rules/index.rst @@ -4,6 +4,7 @@ Suricata Rules .. toctree:: intro + rule-types meta header-keywords payload-keywords diff --git a/doc/userguide/rules/intro/OverallAlgoHorizontal-20241127.png b/doc/userguide/rules/intro/OverallAlgoHorizontal-20241127.png new file mode 100644 index 0000000000000000000000000000000000000000..c273a1380c63b150c66483afb0e69a0a5627c36e GIT binary patch literal 74874 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
es|aO?PQ{oP@aiO5+#zYP}r#!f?lASQ9JEF00 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 zME + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/userguide/rules/rule-types.rst b/doc/userguide/rules/rule-types.rst new file mode 100644 index 000000000000..7fd2a242c3a4 --- /dev/null +++ b/doc/userguide/rules/rule-types.rst @@ -0,0 +1,936 @@ +.. role:: example-rule-action +.. role:: example-rule-header +.. role:: example-rule-options +.. role:: example-rule-emphasis + +Rule Types and Categorization +============================= + +Once parsed, Suricata rules are categorized for performance and further +processing (as different rule types will be handled by specific engine modules). +The signature types are defined in `src/detect.h +`_: + +.. literalinclude:: ../../../src/detect.h + :caption: src/detect.h + :language: c + :start-after: // rule types documentation tag start: SignatureType + :end-before: // rule types documentation tag end: SignatureType + +In more human readable terms: + +.. list-table:: Suricata Rule Types, and their Engine Analysis Term + :header-rows: 1 + + * - Rule Type + - Code Symbol + - Engine-Analysis Representation + * - Decoder Events Only + - ``SIG_TYPE_DEONLY`` + - ``de_only`` + * - Packet + - ``SIG_TYPE_PKT`` + - ``pkt`` + * - IP Only + - ``SIG_TYPE_IPONLY`` + - ``ip_only`` + * - IP Only (contains negated address(es)) + - ``SIG_TYPE_LIKE_IPONLY`` + - ``like_ip_only`` + * - Protocol Detection Only + - ``SIG_TYPE_PDONLY`` + - ``pd_only`` + * - Packet-Stream + - ``SIG_TYPE_PKT_STREAM`` + - ``pkt_stream`` + * - Stream + - ``SIG_TYPE_STREAM`` + - ``stream`` + * - Application Layer Protocol + - ``SIG_TYPE_APPLAYER`` + - ``app_layer`` + * - Application Layer Protocol Transactions + - ``SIG_TYPE_APP_TX`` + - ``app_tx`` + +The rule type will impact: + + - To what does the signature action apply, in case of a match (`Action Scope`) + - When is the rule matched against traffic (`Inspected`) + - Against what the rule matches (`Matches`) + +This categorization is done taking into consideration the presence or absence of +certain rule elements, as well as the type of keywords used. The categorization +currently takes place in `src/detect-engine-build.c:void SignatureSetType() +`_. + +The ``SignatureSetType()`` overall flow is described below: + +.. image:: intro/OverallAlgoHorizontal-20241127.png + :width: 600 + :alt: A flowchart representing the SignatureSetType function. + +The following table lists all Suricata signature types, and how they impact the +aspects aforementioned. + +.. list-table:: Suricata Rule Types + :widths: 10, 17, 18, 30, 25 + :header-rows: 1 + + * - Type + - Action Scope + - Inspected + - Matches + - Keyword Examples (non-exhaustive) + * - Decoder Events Only + - Packet + - Per-packet basis + - Packets that are broken on an IP level + - ``decode-event`` + * - Packet + - Packet + - Per-packet basis + - Packet-level info (e.g.: header info) + - ``itype``, ``tcp.hdr``, ``tcp.seq``, ``ttl`` etc. + * - IP Only + - Flow + - Once per direction + - On IP addresses on the flow + - Source/ Destination field of a rule + * - IP Only (contains negated address)(*) + - Flow + - Once per direction + - On IP addresses on the flow + - Source/ Destination field of a rule, containing negated address + * - Protocol Detection Only + - Flow + - Once per direction, when protocol detection is done + - On protocol detected for the flow + - ``app-layer-protocol`` + * - Packet-Stream + - Flow, if stateful (**) + - Per stream chunk, if stateful, per-packet if not. + - Against the reassembled stream. If stream unavailable, match per-packet. + (stream payload or packet payload) + - ``content`` with ``startswith`` or ``depth`` + * - Stream + - Flow, if stateful (**) + - Per stream chunk, if stateful, per-packet if not. + - Against the reassembled stream. If stream unavailable, match per-packet. + (stream payload or packet payload) + - ``tcp-stream`` in protocol field; simple ``content``; ``byte_extract`` + * - Application Layer Protocol + - Flow + - Per-packet basis + - On 'protocol' field + - `Protocol field `_ of a rule + * - Application Layer Protocol Transactions + - Flow + - Per transaction update + - On buffer keywords + - Application layer protocol-related, e.g. ``http.host``, ``rfb.secresult``, + ``dcerpc.stub_data``, ``frame`` keywords + +.. note:: + (*) IP Only signatures with negated addresses are `like` IP-only signatures, but + currently handled differently due to limitations of the algorithm processing + IP Only rules. + +.. note:: Action Scope: `Flow, if stateful` + + (**) Apply to the flow. If a segment isn't accepted into a stream for any + reason (such as packet anomalies, errors, memcap reached etc), the rule will + be applied on a packet level. + +.. warning:: + + Although both are related to matching on application layer protocols, since + Suricata 7, a Protocol Detection rule (that uses the ``app-layer-protocol`` + keyword) is not internally classified the same as a simple rule matching on + the application layer protocol on the `protocol` field. + + +Signature Properties +-------------------- + +The `Action Scope` mentioned above relates to the Signature Properties, as seen in +`src/detect-engine.c `_: + +.. literalinclude:: ../../../src/detect-engine.c + :caption: src/detect-engine.c + :language: c + :start-after: // rule types documentation tag start: SignatureProperties + :end-before: // rule types documentation tag end: SignatureProperties + +Signature: Require Real Packet +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Aside from the scope of action of a signature, certain rule conditions will +require that it matches against a *real packet* (as opposed to a *pseudo packet*). +These rules are flagged with ``SIG_MASK_REQUIRE_REAL_PKT`` by the engine, and +will have ``real_pkt`` listed as one of the rule's ``requirements``. (See +``engine-analysis`` example output for the `Packet`_ rule type.) + +Signature Types and Variable-like Keywords +------------------------------------------ + +Keywords such as flow variables (``flowint``, ``flowbits``), ``datasets``, +and similar ones can alter the rule type, if present in a signature. + +That happens because the variable condition can change per packet. Thus, the +Signature is categorized as a `packet` rule. + +This affects rule types:: + + - Application Layer (`app_layer`) + - Protocol Detection Only (`pd_only`) + - Decoder Events Only (`de_only`) + +The rule examples provided further cover some such cases, but the table below +lists those keywords with more details: + +.. list-table:: Variable-like Keywords + :header-rows: 1 + + * - Keyword + - Keyword Option + - Rule Type change? + * - ``flow`` + - ``to_server``, ``to_client`` + - no type change + * - ``flow`` + - ``established``, ``not_established`` + - to `packet` + * - ``flowbits``, ``xbits``, ``hostbits`` + - ``isset``, ``isnotset`` + - to `packet` + * - ``flowbits``, ``xbits``, ``hostbits`` + - ``set``, ``unset``, ``toggle`` + - no type change + * - ``flowint`` + - ``isset``, ``notset``, all operators + - to `packet` + * - ``flowint`` + - defining the variable; unseting; + - no type change + * - ``iprep`` + - ``isset``, ``notset``, all operators + - to `packet` + +.. note:: + + ``dataset``, while may look similar to the keywords above, doesn't pertain + to this list as it can only be used with sticky buffer keywords, thus being + only available to Application Layer Transaction rules (`app_tx`), which are + not affected by this. + + +Signature Examples per Type +--------------------------- + +This section ilustrates what rules of each type may look like. It is possible +to learn the type of a signature, as well as other important information, by +running Suricata in :ref:`engine analysis ` mode. + +For each rule type, there is also a sample of the Engine Analysis report +for the shown rule(s). + +Decoder Events Only +^^^^^^^^^^^^^^^^^^^ + +For more examples check https://github.com/OISF/suricata/blob/master/rules/decoder-events.rules. + +.. container:: example-rule + + alert pkthdr any any -> any any (msg:"SURICATA IPv6 duplicated Hop-By-Hop Options extension header"; :example-rule-emphasis:`decode-event:ipv6.exthdr_dupl_hh;` classtype:protocol-command-decode; sid:1101;) + +Engine-Analysis Report +"""""""""""""""""""""" +.. code-block:: json + + { + "raw": "alert pkthdr any any -> any any (msg:\"SURICATA IPv6 duplicated Hop-By-Hop Options extension header\"; decode-event:ipv6.exthdr_dupl_hh; classtype:protocol-command-decode; sid:1101;)", + "id": 1101, + "gid": 1, + "rev": 0, + "msg": "SURICATA IPv6 duplicated Hop-By-Hop Options extension header", + "app_proto": "unknown", + "requirements": [ + "engine_event" + ], + "type": "de_only", + "flags": [ + "src_any", + "dst_any", + "sp_any", + "dp_any", + "toserver", + "toclient" + ], + "pkt_engines": [ + { + "name": "packet", + "is_mpm": false + } + ], + "frame_engines": [], + "lists": { + "packet": { + "matches": [ + { + "name": "decode-event" + } + ] + } + } + } + + +Packet +^^^^^^ + +.. container:: example-rule + + alert udp any any -> any any (msg:"UDP with flow direction"; flow:to_server; sid:1001;) + +.. container:: example-rule + + alert tcp any any -> any any (msg:"ttl"; :example-rule-emphasis:`ttl:123;` sid:701;) + +.. container:: example-rule + + alert tcp-pkt any any -> any any (msg:"tcp-pkt, anchored content"; content:"abc"; startswith; sid:203;) + +Engine-Analysis Report +"""""""""""""""""""""" +.. code-block:: json + + { + "raw": "alert tcp-pkt any any -> any any (msg:\"tcp-pkt, anchored content\"; content:\"abc\"; startswith; sid:203;)", + "id": 203, + "gid": 1, + "rev": 0, + "msg": "tcp-pkt, anchored content", + "app_proto": "unknown", + "requirements": [ + "payload", + "real_pkt" + ], + "type": "pkt", + "flags": [ + "src_any", + "dst_any", + "sp_any", + "dp_any", + "need_packet", + "toserver", + "toclient", + "prefilter" + ], + "pkt_engines": [ + { + "name": "payload", + "is_mpm": true + } + ], + "frame_engines": [], + "lists": { + "payload": { + "matches": [ + { + "name": "content", + "content": { + "pattern": "abc", + "length": 3, + "nocase": false, + "negated": false, + "starts_with": true, + "ends_with": false, + "is_mpm": true, + "no_double_inspect": false, + "depth": 3, + "fast_pattern": false, + "relative_next": false + } + } + ] + } + }, + "mpm": { + "buffer": "payload", + "pattern": "abc", + "length": 3, + "nocase": false, + "negated": false, + "starts_with": true, + "ends_with": false, + "is_mpm": true, + "no_double_inspect": false, + "depth": 3, + "fast_pattern": false, + "relative_next": false + } + } + + +IP Only +^^^^^^^ + +.. container:: example-rule + + alert tcp-stream any any -> any any (msg:"tcp-stream, no content"; sid:101;) + + +.. container:: example-rule + + alert tcp-pkt [192.168.0.0/16,10.0.0.0/8,172.16.0.0/12] any -> any any (msg:"tcp-pkt, no content"; sid:201;) + +.. container:: example-rule + + alert ip any any -> any any (hostbits:set,myflow2; sid:1505;) + +Engine-Analysis Report +"""""""""""""""""""""" +.. code-block:: json + + { + "raw": "alert ip any any -> any any (hostbits:set,myflow2; sid:1505;)", + "id": 1505, + "gid": 1, + "rev": 0, + "app_proto": "unknown", + "requirements": [], + "type": "ip_only", + "flags": [ + "src_any", + "dst_any", + "sp_any", + "dp_any", + "toserver", + "toclient" + ], + "pkt_engines": [], + "frame_engines": [], + "lists": { + "postmatch": { + "matches": [ + { + "name": "hostbits" + } + ] + } + } + } + + +IP Only (contains negated address) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. container:: example-rule + + alert tcp 192.168.0.0/16,10.0.0.0/8,172.16.0.0/12 any -> :example-rule-emphasis:`![192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]` any (msg:"tcp, has negated IP address"; sid:304;) + +.. container:: example-rule + + alert tcp :example-rule-emphasis:`[10.0.0.0/8,!10.10.10.10]` any -> :example-rule-emphasis:`[10.0.0.0/8,!10.10.10.10]` any (msg:"tcp, has negated IP address"; sid:305;) + +Engine-Analysis Report +"""""""""""""""""""""" +.. code-block:: json + + { + "raw": "alert tcp [10.0.0.0/8,!10.10.10.10] any -> [10.0.0.0/8,!10.10.10.10] any (msg:\"tcp, has negated IP address\"; sid:305;)", + "id": 305, + "gid": 1, + "rev": 0, + "msg": "tcp, has negated IP address", + "app_proto": "unknown", + "requirements": [], + "type": "like_ip_only", + "flags": [ + "sp_any", + "dp_any", + "toserver", + "toclient" + ], + "pkt_engines": [], + "frame_engines": [], + "lists": {} + } + +Protocol Detection Only +^^^^^^^^^^^^^^^^^^^^^^^ + +.. container:: example-rule + + alert tcp any any -> any any (msg:"tcp, pd negated"; :example-rule-emphasis:`app-layer-protocol:!http;` sid:401;) + + +.. container:: example-rule + + alert tcp any any -> any any (msg:"tcp, pd positive"; :example-rule-emphasis:`app-layer-protocol:http;` sid:402;) + +.. container:: example-rule + + alert tcp any any -> any any (msg:"tcp, pd positive dns"; :example-rule-emphasis:`app-layer-protocol:dns;` sid:403;) + +Engine-Analysis Report +"""""""""""""""""""""" +.. code-block:: json + + { + "raw": "alert tcp any any -> any any (msg:\"tcp, pd positive dns\"; app-layer-protocol:dns; sid:403;)", + "id": 403, + "gid": 1, + "rev": 0, + "msg": "tcp, pd positive dns", + "app_proto": "unknown", + "requirements": [], + "type": "pd_only", + "flags": [ + "src_any", + "dst_any", + "sp_any", + "dp_any", + "toserver", + "toclient" + ], + "pkt_engines": [ + { + "name": "packet", + "is_mpm": false + } + ], + "frame_engines": [], + "lists": { + "packet": { + "matches": [ + { + "name": "app-layer-protocol" + } + ] + } + } + } + +Packet-Stream +^^^^^^^^^^^^^ + +.. container:: example-rule + + alert tcp any any -> any any (msg:"tcp, anchored content"; :example-rule-emphasis:`content:"abc"; startswith;` sid:303;) + +.. container:: example-rule + + alert http any any -> any any (msg:"http, anchored content"; :example-rule-emphasis:`content:"abc"; depth:30;` sid:603;) + +Engine-Analysis Report +"""""""""""""""""""""" +.. collapse:: click to expand Engine-Analysis Report + + .. code-block:: json + + { + "raw": "alert http any any -> any any (msg:\"http, anchored content\"; content:\"abc\"; depth:30; sid:603;)", + "id": 603, + "gid": 1, + "rev": 0, + "msg": "http, anchored content", + "app_proto": "http_any", + "requirements": [ + "payload", + "flow" + ], + "type": "pkt_stream", + "flags": [ + "src_any", + "dst_any", + "sp_any", + "dp_any", + "applayer", + "need_packet", + "need_stream", + "toserver", + "toclient", + "prefilter" + ], + "pkt_engines": [ + { + "name": "payload", + "is_mpm": true + } + ], + "frame_engines": [], + "lists": { + "payload": { + "matches": [ + { + "name": "content", + "content": { + "pattern": "abc", + "length": 3, + "nocase": false, + "negated": false, + "starts_with": false, + "ends_with": false, + "is_mpm": true, + "no_double_inspect": false, + "depth": 30, + "fast_pattern": false, + "relative_next": false + } + } + ] + } + }, + "mpm": { + "buffer": "payload", + "pattern": "abc", + "length": 3, + "nocase": false, + "negated": false, + "starts_with": false, + "ends_with": false, + "is_mpm": true, + "no_double_inspect": false, + "depth": 30, + "fast_pattern": false, + "relative_next": false + } + } + + +Stream +^^^^^^ + +.. container:: example-rule + + alert :example-rule-emphasis:`tcp-stream` any any -> any any (msg:"tcp-stream, simple content"; :example-rule-emphasis:`content:"abc";` sid:102;) + +.. container:: example-rule + + alert :example-rule-emphasis:`http` any any -> any any (msg:"http, simple content"; :example-rule-emphasis:`content:"abc";` sid:602;) + +.. container:: example-rule + + alert :example-rule-emphasis:`tcp` any any -> any any (msg:"byte_extract with dce"; :example-rule-emphasis:`byte_extract:4,0,var,dce; byte_test:4,>,var,4,little;` sid:901;) + +Engine-Analysis Report +"""""""""""""""""""""" +.. code-block:: json + + { + "raw": "alert tcp any any -> any any (msg:\"byte_extract with dce\"; byte_extract:4,0,var,dce; byte_test:4,>,var,4,little; sid:901;)", + "id": 901, + "gid": 1, + "rev": 0, + "msg": "byte_extract with dce", + "app_proto": "dcerpc", + "requirements": [ + "payload", + "flow" + ], + "type": "stream", + "flags": [ + "src_any", + "dst_any", + "sp_any", + "dp_any", + "applayer", + "need_stream", + "toserver", + "toclient" + ], + "pkt_engines": [ + { + "name": "payload", + "is_mpm": false + } + ], + "frame_engines": [], + "lists": { + "payload": { + "matches": [ + { + "name": "byte_extract" + }, + { + "name": "byte_test", + "byte_test": { + "nbytes": 4, + "offset": 4, + "base": "unset", + "flags": [ + "little_endian" + ] + } + } + ] + } + } + } + +Application Layer Protocol +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. container:: example-rule + + alert :example-rule-emphasis:`http` any any -> any any (msg:"http, no content"; sid:601;) + +.. container:: example-rule + + alert :example-rule-emphasis:`dns` any any -> any any (msg:"app-layer, dns"; sid:404;) + +.. warning:: + + As per Suricata 7, if ``flow:established`` or ``flow:not_established`` is added to an + Application Layer Protocol rule, that signature is now categorized as a `Packet`_ rule. + +Engine-Analysis Report +"""""""""""""""""""""" +.. collapse:: click to expand Engine-Analysis Report + + .. code-block:: json + + { + "raw": "alert dns any any -> any any (msg:\"app-layer, dns\"; sid:404;)", + "id": 404, + "gid": 1, + "rev": 0, + "msg": "app-layer, dns", + "app_proto": "dns", + "requirements": [ + "flow" + ], + "type": "app_layer", + "flags": [ + "src_any", + "dst_any", + "sp_any", + "dp_any", + "applayer", + "toserver", + "toclient" + ], + "pkt_engines": [], + "frame_engines": [], + "lists": {} + } + +Application Layer Protocol Transactions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. container:: example-rule + + alert tcp any any -> any any (msg:"http, pos event"; :example-rule-emphasis:`app-layer-event:http.file_name_too_long;` sid:501;) + +.. container:: example-rule + + alert http any any -> any any (msg:"Test"; flow:established,to_server; :example-rule-emphasis:`http.method; content:"GET"; http.uri; content:".exe";` endswith; :example-rule-emphasis:`http.host; content:!".google.com";` endswith; sid:1102;) + +.. container:: example-rule + + alert udp any any -> any any (msg:"DNS UDP Frame"; flow:to_server; :example-rule-emphasis:`frame:dns.pdu;` content:"\|01 20 00 01\|"; offset:2; content:"suricata"; offset:13; sid:1402; rev:1;) + +.. container:: example-rule + + alert tcp any any -> any any (msg:"byte_extract with dce"; dcerpc.stub_data; content:"abc"; byte_extract:4,0,var,relative; byte_test:4,>,var,4,little; sid:902;) + +Engine-Analysis Report +"""""""""""""""""""""" +.. collapse:: click to expand Engine-Analysis Report + + .. code-block:: json + + { + "raw": "alert tcp any any -> any any (msg:\"byte_extract with dce\"; dcerpc.stub_data; content:\"abc\"; byte_extract:4,0,var,relative; byte_test:4,>,var,4,little; sid:902;)", + "id": 902, + "gid": 1, + "rev": 0, + "msg": "byte_extract with dce", + "app_proto": "dcerpc", + "requirements": [ + "flow" + ], + "type": "app_tx", + "flags": [ + "src_any", + "dst_any", + "sp_any", + "dp_any", + "applayer", + "toserver", + "toclient", + "prefilter" + ], + "pkt_engines": [], + "frame_engines": [], + "engines": [ + { + "name": "dce_stub_data", + "direction": "toclient", + "is_mpm": true, + "app_proto": "dcerpc", + "progress": 0, + "matches": [ + { + "name": "content", + "content": { + "pattern": "abc", + "length": 3, + "nocase": false, + "negated": false, + "starts_with": false, + "ends_with": false, + "is_mpm": true, + "no_double_inspect": false, + "fast_pattern": false, + "relative_next": true + } + }, + { + "name": "byte_extract" + }, + { + "name": "byte_test", + "byte_test": { + "nbytes": 4, + "offset": 4, + "base": "unset", + "flags": [ + "little_endian" + ] + } + } + ] + }, + { + "name": "dce_stub_data", + "direction": "toserver", + "is_mpm": true, + "app_proto": "dcerpc", + "progress": 0, + "matches": [ + { + "name": "content", + "content": { + "pattern": "abc", + "length": 3, + "nocase": false, + "negated": false, + "starts_with": false, + "ends_with": false, + "is_mpm": true, + "no_double_inspect": false, + "fast_pattern": false, + "relative_next": true + } + }, + { + "name": "byte_extract" + }, + { + "name": "byte_test", + "byte_test": { + "nbytes": 4, + "offset": 4, + "base": "unset", + "flags": [ + "little_endian" + ] + } + } + ] + }, + { + "name": "dce_stub_data", + "direction": "toclient", + "is_mpm": true, + "app_proto": "smb", + "progress": 0, + "matches": [ + { + "name": "content", + "content": { + "pattern": "abc", + "length": 3, + "nocase": false, + "negated": false, + "starts_with": false, + "ends_with": false, + "is_mpm": true, + "no_double_inspect": false, + "fast_pattern": false, + "relative_next": true + } + }, + { + "name": "byte_extract" + }, + { + "name": "byte_test", + "byte_test": { + "nbytes": 4, + "offset": 4, + "base": "unset", + "flags": [ + "little_endian" + ] + } + } + ] + }, + { + "name": "dce_stub_data", + "direction": "toserver", + "is_mpm": true, + "app_proto": "smb", + "progress": 0, + "matches": [ + { + "name": "content", + "content": { + "pattern": "abc", + "length": 3, + "nocase": false, + "negated": false, + "starts_with": false, + "ends_with": false, + "is_mpm": true, + "no_double_inspect": false, + "fast_pattern": false, + "relative_next": true + } + }, + { + "name": "byte_extract" + }, + { + "name": "byte_test", + "byte_test": { + "nbytes": 4, + "offset": 4, + "base": "unset", + "flags": [ + "little_endian" + ] + } + } + ] + } + ], + "lists": {}, + "mpm": { + "buffer": "dce_stub_data", + "pattern": "abc", + "length": 3, + "nocase": false, + "negated": false, + "starts_with": false, + "ends_with": false, + "is_mpm": true, + "no_double_inspect": false, + "fast_pattern": false, + "relative_next": true + } + } diff --git a/libhtp/.github/workflows/builds.yml b/libhtp/.github/workflows/builds.yml new file mode 100644 index 000000000000..52b4985146c1 --- /dev/null +++ b/libhtp/.github/workflows/builds.yml @@ -0,0 +1,110 @@ +name: builds + +on: + - push + - pull_request + +permissions: read-all + +env: + DEFAULT_CFLAGS: "-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-function" + + # Apt sometimes likes to ask for user input, this will prevent that. + DEBIAN_FRONTEND: "noninteractive" + +jobs: + almalinux-9: + name: AlmaLinux 9 + runs-on: ubuntu-latest + container: almalinux:9 + steps: + - uses: actions/checkout@v3.1.0 + - name: Install system dependencies + run: | + dnf -y install make \ + autoconf \ + automake \ + libtool \ + gcc \ + gcc-c++ \ + make \ + pkgconfig \ + zlib-devel + - run: ./autogen.sh + - run: CFLAGS="${DEFAULT_CFLAGS}" ./configure + - run: make -j2 + - run: make install + - run: make distcheck + + almalinux-8: + name: AlmaLinux 8 + runs-on: ubuntu-latest + container: almalinux:8 + steps: + - uses: actions/checkout@v3.1.0 + - name: Install system dependencies + run: | + dnf -y install make \ + autoconf \ + automake \ + libtool \ + gcc \ + gcc-c++ \ + make \ + pkgconfig \ + zlib-devel + - run: ./autogen.sh + - run: CFLAGS="${DEFAULT_CFLAGS}" ./configure + - run: make -j2 + - run: make install + - run: make distcheck + + ubuntu-2004: + name: Ubuntu 20.04 + runs-on: ubuntu-latest + container: ubuntu:20.04 + steps: + - uses: actions/checkout@v3.1.0 + - name: Install system dependencies + run: | + apt update + apt-get upgrade -y + apt-get -y install make \ + autoconf \ + build-essential \ + automake \ + dpkg-dev \ + debhelper \ + libtool \ + make \ + pkg-config \ + zlib1g-dev + - run: ./autogen.sh + - run: CFLAGS="${DEFAULT_CFLAGS}" ./configure + - run: make -j2 + - run: make install + - run: make distcheck + + ubuntu-2204: + name: Ubuntu 22.04 + runs-on: ubuntu-latest + container: ubuntu:22.04 + steps: + - uses: actions/checkout@v3.1.0 + - name: Install system dependencies + run: | + apt update + apt-get upgrade -y + apt-get -y install make \ + autoconf \ + build-essential \ + automake \ + libtool \ + make \ + pkg-config \ + zlib1g-dev + - run: ./autogen.sh + - run: CFLAGS="${DEFAULT_CFLAGS}" ./configure + - run: make -j2 + - run: make install + - run: make distcheck diff --git a/src/detect-engine.c b/src/detect-engine.c index f4195739e2c1..272a2c05fe7f 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -110,6 +110,7 @@ static DetectEnginePktInspectionEngine *g_pkt_inspect_engines = NULL; static DetectEngineFrameInspectionEngine *g_frame_inspect_engines = NULL; // clang-format off +// rule types documentation tag start: SignatureProperties const struct SignatureProperties signature_properties[SIG_TYPE_MAX] = { /* SIG_TYPE_NOT_SET */ { SIG_PROP_FLOW_ACTION_PACKET, }, /* SIG_TYPE_IPONLY */ { SIG_PROP_FLOW_ACTION_FLOW, }, @@ -122,6 +123,7 @@ const struct SignatureProperties signature_properties[SIG_TYPE_MAX] = { /* SIG_TYPE_APPLAYER */ { SIG_PROP_FLOW_ACTION_FLOW, }, /* SIG_TYPE_APP_TX */ { SIG_PROP_FLOW_ACTION_FLOW, }, }; +// rule types documentation tag end: SignatureProperties // clang-format on /** \brief register inspect engine at start up time diff --git a/src/detect.h b/src/detect.h index e88b5540ac79..38af8f022b62 100644 --- a/src/detect.h +++ b/src/detect.h @@ -59,6 +59,7 @@ struct SCSigOrderFunc_; /* Forward declarations for structures from Rust. */ typedef struct SCDetectRequiresStatus SCDetectRequiresStatus; +// rule types documentation tag start: SignatureType enum SignatureType { SIG_TYPE_NOT_SET = 0, SIG_TYPE_IPONLY, // rule is handled by IPONLY engine @@ -76,6 +77,7 @@ enum SignatureType { SIG_TYPE_MAX, }; +// rule types documentation tag end: SignatureType enum SignaturePropertyFlowAction { SIG_PROP_FLOW_ACTION_PACKET,