summaryrefslogtreecommitdiffstats
path: root/doc/userguide/rules
diff options
context:
space:
mode:
Diffstat (limited to 'doc/userguide/rules')
-rw-r--r--doc/userguide/rules/app-layer.rst80
-rw-r--r--doc/userguide/rules/base64-keywords.rst64
-rw-r--r--doc/userguide/rules/bypass-keyword.rst19
-rw-r--r--doc/userguide/rules/config.rst44
-rw-r--r--doc/userguide/rules/dataset-examples/detect-unique-tlds.pngbin0 -> 28362 bytes
-rw-r--r--doc/userguide/rules/datasets.rst350
-rw-r--r--doc/userguide/rules/dcerpc-keywords.rst71
-rw-r--r--doc/userguide/rules/dhcp-keywords.rst59
-rw-r--r--doc/userguide/rules/differences-from-snort.rst705
-rw-r--r--doc/userguide/rules/dnp3-keywords.rst149
-rw-r--r--doc/userguide/rules/dns-keywords.rst74
-rw-r--r--doc/userguide/rules/dns-keywords/dns_query.pngbin0 -> 7022 bytes
-rw-r--r--doc/userguide/rules/enip-keyword.rst40
-rw-r--r--doc/userguide/rules/fast-pattern-explained.rst99
-rw-r--r--doc/userguide/rules/fast-pattern/fast_pattern.pngbin0 -> 11808 bytes
-rw-r--r--doc/userguide/rules/file-keywords.rst265
-rw-r--r--doc/userguide/rules/flow-keywords.rst308
-rw-r--r--doc/userguide/rules/flow-keywords/Flow1.pngbin0 -> 24838 bytes
-rw-r--r--doc/userguide/rules/flow-keywords/Flow2.pngbin0 -> 26325 bytes
-rw-r--r--doc/userguide/rules/flow-keywords/Flowbit_3.pngbin0 -> 57320 bytes
-rw-r--r--doc/userguide/rules/ftp-keywords.rst31
-rw-r--r--doc/userguide/rules/header-keywords.rst732
-rw-r--r--doc/userguide/rules/header-keywords/Wireshark_ack.pngbin0 -> 134829 bytes
-rw-r--r--doc/userguide/rules/header-keywords/Wireshark_seq.pngbin0 -> 134801 bytes
-rw-r--r--doc/userguide/rules/http-keywords.rst846
-rw-r--r--doc/userguide/rules/http-keywords/Legenda_rules.pngbin0 -> 13544 bytes
-rw-r--r--doc/userguide/rules/http-keywords/client_body.pngbin0 -> 18115 bytes
-rw-r--r--doc/userguide/rules/http-keywords/client_body1.pngbin0 -> 39183 bytes
-rw-r--r--doc/userguide/rules/http-keywords/cookie.pngbin0 -> 40424 bytes
-rw-r--r--doc/userguide/rules/http-keywords/cookie1.pngbin0 -> 48347 bytes
-rw-r--r--doc/userguide/rules/http-keywords/fast_pattern.pngbin0 -> 11808 bytes
-rw-r--r--doc/userguide/rules/http-keywords/file_data.pngbin0 -> 11858 bytes
-rw-r--r--doc/userguide/rules/http-keywords/header.pngbin0 -> 16340 bytes
-rw-r--r--doc/userguide/rules/http-keywords/header1.pngbin0 -> 38150 bytes
-rw-r--r--doc/userguide/rules/http-keywords/http_server_body.pngbin0 -> 9187 bytes
-rw-r--r--doc/userguide/rules/http-keywords/http_uri.pngbin0 -> 54871 bytes
-rw-r--r--doc/userguide/rules/http-keywords/method.pngbin0 -> 15701 bytes
-rw-r--r--doc/userguide/rules/http-keywords/method1.pngbin0 -> 24326 bytes
-rw-r--r--doc/userguide/rules/http-keywords/method2.pngbin0 -> 18669 bytes
-rw-r--r--doc/userguide/rules/http-keywords/stat-code1.pngbin0 -> 25336 bytes
-rw-r--r--doc/userguide/rules/http-keywords/stat_code.pngbin0 -> 2295 bytes
-rw-r--r--doc/userguide/rules/http-keywords/stat_msg.pngbin0 -> 2009 bytes
-rw-r--r--doc/userguide/rules/http-keywords/stat_msg_1.pngbin0 -> 25055 bytes
-rw-r--r--doc/userguide/rules/http-keywords/uri.pngbin0 -> 23158 bytes
-rw-r--r--doc/userguide/rules/http-keywords/uri1.pngbin0 -> 5020 bytes
-rw-r--r--doc/userguide/rules/http-keywords/uricontent1.pngbin0 -> 6263 bytes
-rw-r--r--doc/userguide/rules/http-keywords/urilen.pngbin0 -> 26395 bytes
-rw-r--r--doc/userguide/rules/http-keywords/user_agent.pngbin0 -> 30094 bytes
-rw-r--r--doc/userguide/rules/http-keywords/user_agent_match.pngbin0 -> 270675 bytes
-rw-r--r--doc/userguide/rules/http2-keywords.rst118
-rw-r--r--doc/userguide/rules/ike-keywords.rst159
-rw-r--r--doc/userguide/rules/index.rst46
-rw-r--r--doc/userguide/rules/intro.rst319
-rw-r--r--doc/userguide/rules/intro/TCP-session.pngbin0 -> 37144 bytes
-rw-r--r--doc/userguide/rules/ip-reputation-rules.rst45
-rw-r--r--doc/userguide/rules/ipaddr.rst31
-rw-r--r--doc/userguide/rules/ja3-keywords.rst73
-rw-r--r--doc/userguide/rules/kerberos-keywords.rst140
-rw-r--r--doc/userguide/rules/lua-detection.rst104
-rw-r--r--doc/userguide/rules/meta.rst261
-rw-r--r--doc/userguide/rules/modbus-keyword.rst131
-rw-r--r--doc/userguide/rules/mqtt-keywords.rst264
-rw-r--r--doc/userguide/rules/multi-buffer-matching.rst92
-rw-r--r--doc/userguide/rules/normalized-buffers/normalization1.pngbin0 -> 24182 bytes
-rw-r--r--doc/userguide/rules/payload-keywords.rst844
-rw-r--r--doc/userguide/rules/payload-keywords/Legenda_rules.pngbin0 -> 13544 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/content2.pngbin0 -> 16267 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/content3.pngbin0 -> 17931 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/content4.pngbin0 -> 20218 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/content5.pngbin0 -> 17117 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/content6.pngbin0 -> 28424 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/distance.pngbin0 -> 17835 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/distance1.pngbin0 -> 22147 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/distance3.pngbin0 -> 11561 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/distance4.pngbin0 -> 28159 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/distance5.pngbin0 -> 18506 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/isdataat1.pngbin0 -> 18472 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/replace.pngbin0 -> 5595 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/replace1.pngbin0 -> 7628 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/within1.pngbin0 -> 18170 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/within2.pngbin0 -> 25136 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/within_distance.pngbin0 -> 14888 bytes
-rw-r--r--doc/userguide/rules/payload-keywords/within_distance2.pngbin0 -> 13234 bytes
-rw-r--r--doc/userguide/rules/pcre/pcre3.pngbin0 -> 21204 bytes
-rw-r--r--doc/userguide/rules/pcre/pcre4.pngbin0 -> 22114 bytes
-rw-r--r--doc/userguide/rules/pcre/pcre5.pngbin0 -> 20860 bytes
-rw-r--r--doc/userguide/rules/pcre/pcre6.pngbin0 -> 22648 bytes
-rw-r--r--doc/userguide/rules/prefilter-keywords.rst81
-rw-r--r--doc/userguide/rules/quic-keywords.rst54
-rw-r--r--doc/userguide/rules/rfb-keywords.rst56
-rw-r--r--doc/userguide/rules/sip-keywords.rst179
-rw-r--r--doc/userguide/rules/smb-keywords.rst60
-rw-r--r--doc/userguide/rules/snmp-keywords.rst95
-rw-r--r--doc/userguide/rules/ssh-keywords.rst149
-rw-r--r--doc/userguide/rules/tag.rst133
-rw-r--r--doc/userguide/rules/thresholding.rst118
-rw-r--r--doc/userguide/rules/tls-keywords.rst304
-rw-r--r--doc/userguide/rules/transforms.rst190
-rw-r--r--doc/userguide/rules/xbits.rst108
99 files changed, 8090 insertions, 0 deletions
diff --git a/doc/userguide/rules/app-layer.rst b/doc/userguide/rules/app-layer.rst
new file mode 100644
index 0000000..8295d58
--- /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:[!]<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:<event name>;
+
+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/base64-keywords.rst b/doc/userguide/rules/base64-keywords.rst
new file mode 100644
index 0000000..7daf0c2
--- /dev/null
+++ b/doc/userguide/rules/base64-keywords.rst
@@ -0,0 +1,64 @@
+Base64 keywords
+===============
+
+Suricata supports decoding base64 encoded data from buffers and matching on the decoded data.
+
+This is achieved by using two keywords, ``base64_decode`` and ``base64_data``. Both keywords must be used in order to generate an alert.
+
+base64_decode
+-------------
+
+Decodes base64 data from a buffer and makes it available for the base64_data function.
+
+Syntax::
+
+ base64_decode:bytes <value>, offset <value>, relative;
+
+The ``bytes`` option specifies how many bytes Suricata should decode and make available for base64_data.
+The decoding will stop at the end of the buffer.
+
+The ``offset`` option specifies how many bytes Suricata should skip before decoding.
+Bytes are skipped relative to the start of the payload buffer if the ``relative`` is not set.
+
+The ``relative`` option makes the decoding start relative to the previous content match. Default behavior is to start at the beginning of the buffer.
+This option makes ``offset`` skip bytes relative to the previous match.
+
+.. note:: Regarding ``relative`` and ``base64_decode``:
+
+ The content match that you want to decode relative to must be the first match in the stream.
+
+.. note:: ``base64_decode`` follows RFC 4648 by default i.e. encounter with any character that is not found in the base64 alphabet leads to rejection of that character and the rest of the string.
+
+ See Redmine Bug 5223: https://redmine.openinfosecfoundation.org/issues/5223 and RFC 4648: https://www.rfc-editor.org/rfc/rfc4648#section-3.3
+
+base64_data
+-----------
+
+base64_data is a ``sticky buffer``.
+
+Enables content matching on the data previously decoded by base64_decode.
+
+Example
+-------
+
+Here is an example of a rule matching on the base64 encoded string "test" that is found inside the http_uri buffer.
+
+It starts decoding relative to the known string "somestring" with the known offset of 1. This must be the first occurrence of "somestring" in the buffer.
+
+Example::
+
+ Buffer content:
+ http_uri = "GET /en/somestring&dGVzdAo=&not_base64"
+
+ Rule:
+ alert http any any -> any any (msg:"Example"; http.uri; content:"somestring"; \
+ base64_decode:bytes 8, offset 1, relative; \
+ base64_data; content:"test"; sid:10001; rev:1;)
+
+ Buffer content:
+ http_uri = "GET /en/somestring&dGVzdAo=&not_base64"
+
+ Rule:
+ alert http any any -> any any (msg:"Example"; content:"somestring"; http_uri; \
+ base64_decode:bytes 8, offset 1, relative; \
+ base64_data; content:"test"; sid:10001; rev:1;)
diff --git a/doc/userguide/rules/bypass-keyword.rst b/doc/userguide/rules/bypass-keyword.rst
new file mode 100644
index 0000000..e5505a6
--- /dev/null
+++ b/doc/userguide/rules/bypass-keyword.rst
@@ -0,0 +1,19 @@
+Bypass Keyword
+==============
+
+Suricata has a ``bypass`` keyword that can be used in signatures to exclude traffic from further evaluation.
+
+The ``bypass`` keyword is useful in cases where there is a large flow expected (e.g. Netflix, Spotify, YouTube).
+
+The ``bypass`` keyword is considered a post-match keyword.
+
+
+bypass
+------
+
+Bypass a flow on matching http traffic.
+
+Example::
+
+ alert http any any -> any any (content:"suricata.io"; \
+ http_host; bypass; sid:10001; rev:1;)
diff --git a/doc/userguide/rules/config.rst b/doc/userguide/rules/config.rst
new file mode 100644
index 0000000..2603643
--- /dev/null
+++ b/doc/userguide/rules/config.rst
@@ -0,0 +1,44 @@
+Config Rules
+============
+
+Config rules are rules that when matching, will change the configuration of
+Suricata for a flow, transaction, packet or other unit.
+
+Example::
+
+ config dns any any -> any any (dns.query; content:"suricata"; config: logging disable, type tx, scope tx; sid:1;)
+
+This example will detect if a DNS query contains the string `suricata` and if
+so disable the DNS transaction logging. This means that `eve.json` records,
+but also Lua output, will not be generated/triggered for this DNS transaction.
+
+Keyword
+-------
+
+The `config` rule keyword provides the setting and the scope of the change.
+
+Syntax::
+
+ config:<subsys> <action>, type <type>, scope <scope>;
+
+`subsys` can be set to:
+
+* `logging` setting affects logging.
+
+`type` can be set to:
+
+* `tx` sub type of the `subsys`. If `subsys` is set to `logging`, setting the `type` to `tx` means transaction logging is affected.
+
+`scope` can be set to:
+
+* `tx` setting affects the matching transaction.
+
+The `action` in `<subsys>` is currently limited to `disable`.
+
+
+Action
+------
+
+Config rules can, but don't have to, use the `config` rule action. The `config`
+rule action won't generate an alert when the rule matches, but the rule actions
+will still be applied. It is equivalent to `alert ... (noalert; ...)`.
diff --git a/doc/userguide/rules/dataset-examples/detect-unique-tlds.png b/doc/userguide/rules/dataset-examples/detect-unique-tlds.png
new file mode 100644
index 0000000..78b862f
--- /dev/null
+++ b/doc/userguide/rules/dataset-examples/detect-unique-tlds.png
Binary files differ
diff --git a/doc/userguide/rules/datasets.rst b/doc/userguide/rules/datasets.rst
new file mode 100644
index 0000000..069ee72
--- /dev/null
+++ b/doc/userguide/rules/datasets.rst
@@ -0,0 +1,350 @@
+.. _datasets:
+
+Datasets
+========
+
+Using the ``dataset`` and ``datarep`` keyword it is possible to match on
+large amounts of data against any sticky buffer.
+
+For example, to match against a DNS black list called ``dns-bl``::
+
+ dns.query; dataset:isset,dns-bl;
+
+These keywords are aware of transforms. So to look up a DNS query against
+a MD5 black list::
+
+ dns.query; to_md5; dataset:isset,dns-bl;
+
+Global config (optional)
+------------------------
+
+Datasets can optionally be defined in the main config. Sets can also be
+declared from the rule syntax.
+
+Example of sets for tracking unique values::
+
+ datasets:
+ ua-seen:
+ type: string
+ state: ua-seen.lst
+ dns-sha256-seen:
+ type: sha256
+ state: dns-sha256-seen.lst
+
+Rules to go with the above:
+
+.. container:: example-rule
+
+ alert dns any any -> any any (msg:"dns list test"; dns.query; to_sha256; dataset:isset,dns-sha256-seen; sid:123; rev:1;)
+
+.. container:: example-rule
+
+ alert http any any -> any any (msg: "http user-agent test"; http.user_agent; dataset:set,ua-seen; sid:234; rev:1;)
+
+It is also possible to optionally define global default memcap and hashsize.
+
+Example::
+
+ datasets:
+ defaults:
+ memcap: 100mb
+ hashsize: 2048
+ ua-seen:
+ type: string
+ load: ua-seen.lst
+
+or define memcap and hashsize per dataset.
+
+Example::
+
+ datasets:
+ ua-seen:
+ type: string
+ load: ua-seen.lst
+ memcap: 10mb
+ hashsize: 1024
+
+.. note:: The `hashsize` should be close to the amount of entries in the dataset to avoid collisions. If it's set too low, this could result in rather long startup time.
+
+Rule keywords
+-------------
+
+dataset
+~~~~~~~
+
+Datasets are binary: something is in the set or it's not.
+
+Syntax::
+
+ dataset:<cmd>,<name>,<options>;
+
+ dataset:<set|isset|isnotset>,<name> \
+ [, type <string|md5|sha256|ipv4|ip>, save <file name>, load <file name>, state <file name>, memcap <size>, hashsize <size>];
+
+type <type>
+ the data type: string, md5, sha256, ipv4, ip
+load <file name>
+ file name for load the data when Suricata starts up
+state
+ sets file name for loading and saving a dataset
+save <file name>
+ advanced option to set the file name for saving the in-memory data
+ when Suricata exits.
+memcap <size>
+ maximum memory limit for the respective dataset
+hashsize <size>
+ allowed size of the hash for the respective dataset
+
+.. note:: 'type' is mandatory and needs to be set.
+
+.. note:: 'load' and 'state' or 'save' and 'state' cannot be mixed.
+
+Example rules could look like:
+
+1. Detect unique User-Agents:
+
+.. container:: example-rule
+
+ alert http any any -> any any (msg:"LOCAL HTTP new UA"; http.user_agent; dataset:set,http-ua-seen, type string, state http-ua-seen.csv; sid:8000001; rev:1;)
+
+2. Detect unique TLDs:
+
+.. container:: example-rule
+
+ alert dns $HOME_NET any -> any any (msg:"LOCAL DNS unique TLD"; dns.query; pcrexform:"\\.([^\\.]+)$"; dataset:set,dns-tld-seen, type string, state dns-tld-seen.csv; sid:8000002; rev:1;)
+
+Following image is a pictorial representation of how the ``pcrexform`` works
+on domain names to find TLDs in the dataset ``dns-tld-seen``:
+
+.. image:: dataset-examples/detect-unique-tlds.png
+
+Notice how it is not possible to do certain operations alone with datasets
+(example 2 above), but, it is possible to use a combination of other rule
+keywords. Keep in mind the cost of additional keywords though e.g. in the
+second example rule above, negative performance impact can be expected due
+to ``pcrexform``.
+
+datarep
+~~~~~~~
+
+Data Reputation allows matching data against a reputation list.
+
+Syntax::
+
+ datarep:<name>,<operator>,<value>, \
+ [, load <file name>, type <string|md5|sha256|ipv4|ip>, memcap <size>, hashsize <size>];
+
+Example rules could look like::
+
+ alert dns any any -> any any (dns.query; to_md5; datarep:dns_md5, >, 200, load dns_md5.rep, type md5, memcap 100mb, hashsize 2048; sid:1;)
+ alert dns any any -> any any (dns.query; to_sha256; datarep:dns_sha256, >, 200, load dns_sha256.rep, type sha256; sid:2;)
+ alert dns any any -> any any (dns.query; datarep:dns_string, >, 200, load dns_string.rep, type string; sid:3;)
+
+In these examples the DNS query string is checked against three different
+reputation lists. A MD5 list, a SHA256 list, and a raw string (buffer) list.
+The rules will only match if the data is in the list and the reputation
+value is higher than 200.
+
+
+Rule Reloads
+------------
+
+Sets that are defined in the yaml, or sets that only use `state` or `save`, are
+considered `dynamic` sets. These are not reloaded during rule reloads.
+
+Sets that are defined in rules using only `load` are considered `static` tests.
+These are not expected to change during runtime. During rule reloads these are
+reloaded from disk. This reload is effective when the complete rule reload
+process is complete.
+
+
+Unix Socket
+-----------
+
+dataset-add
+~~~~~~~~~~~
+
+Unix Socket command to add data to a set. On success, the addition becomes
+active instantly.
+
+Syntax::
+
+ dataset-add <set name> <set type> <data>
+
+set name
+ Name of an already defined dataset
+type
+ Data type: string, md5, sha256, ipv4, ip
+data
+ Data to add in serialized form (base64 for string, hex notation for md5/sha256, string representation for ipv4/ip)
+
+Example adding 'google.com' to set 'myset'::
+
+ dataset-add myset string Z29vZ2xlLmNvbQ==
+
+dataset-remove
+~~~~~~~~~~~~~~
+
+Unix Socket command to remove data from a set. On success, the removal becomes
+active instantly.
+
+Syntax::
+
+ dataset-remove <set name> <set type> <data>
+
+set name
+ Name of an already defined dataset
+type
+ Data type: string, md5, sha256, ipv4, ip
+data
+ Data to remove in serialized form (base64 for string, hex notation for md5/sha256, string representation for ipv4/ip)
+
+dataset-clear
+~~~~~~~~~~~~~
+
+Unix Socket command to remove all data from a set. On success, the removal becomes
+active instantly.
+
+Syntax::
+
+ dataset-clear <set name> <set type>
+
+set name
+ Name of an already defined dataset
+type
+ Data type: string, md5, sha256, ipv4, ip
+
+dataset-lookup
+~~~~~~~~~~~~~~
+
+Unix Socket command to test if data is in a set.
+
+Syntax::
+
+ dataset-lookup <set name> <set type> <data>
+
+set name
+ Name of an already defined dataset
+type
+ Data type: string, md5, sha256, ipv4, ip
+data
+ Data to test in serialized form (base64 for string, hex notation for md5/sha256, string notation for ipv4/ip)
+
+Example testing if 'google.com' is in the set 'myset'::
+
+ dataset-lookup myset string Z29vZ2xlLmNvbQ==
+
+dataset-dump
+~~~~~~~~~~~~
+
+Unix socket command to trigger a dump of datasets to disk.
+
+Syntax::
+
+ dataset-dump
+
+File formats
+------------
+
+Datasets use a simple CSV format where data is per line in the file.
+
+data types
+~~~~~~~~~~
+
+string
+ in the file as base64 encoded string
+md5
+ in the file as hex encoded string
+sha256
+ in the file as hex encoded string
+ipv4
+ in the file as string
+ip
+ in the file as string, it can be IPv6 or IPv4 address (standard notation or IPv4 in IPv6 one)
+
+
+dataset
+~~~~~~~
+
+Datasets have a simple structure, where there is one piece of data
+per line in the file.
+
+Syntax::
+
+ <data>
+
+e.g. for ua-seen with type string::
+
+ TW96aWxsYS80LjAgKGNvbXBhdGlibGU7ICk=
+
+which when piped to ``base64 -d`` reveals its value::
+
+ Mozilla/4.0 (compatible; )
+
+
+datarep
+~~~~~~~
+
+The datarep format follows the dataset, expect that there are 1 more CSV
+field:
+
+Syntax::
+
+ <data>,<value>
+
+.. _datasets_file_locations:
+
+File Locations
+--------------
+
+Dataset filenames configured in the ``suricata.yaml`` can exist
+anywhere on your filesytem.
+
+When a dataset filename is specified in rule, the following *rules*
+are applied:
+
+- For ``load``, the filename is opened relative to the rule file
+ containing the rule. Absolute filenames and parent directory
+ traversals are allowed.
+- For ``save`` and ``state`` the filename is relative to
+ ``$LOCALSTATEDIR/suricata/data``. On many installs this will be
+ ``/var/lib/suricata/data``, but run ``suricata --build-info`` and
+ check the value of ``--localstatedir`` to verify this location onn
+ your installation.
+
+ - Absolute filenames, or filenames containing parent directory
+ traversal (``..``) are not allowed unless the configuration
+ paramater ``datasets.allow-absolute-filenames`` is set to
+ ``true``.
+
+.. _datasets_security:
+
+Security
+--------
+
+As datasets potentially allow a rule distributor write access to your
+system with ``save`` and ``state`` dataset rules, the locations
+allowed are strict by default, however there are two dataset options
+to tune the security of rules utilizing dataset filenames::
+
+ datasets:
+ rules:
+ # Set to true to allow absolute filenames and filenames that use
+ # ".." components to reference parent directories in rules that specify
+ # their filenames.
+ allow-absolute-filenames: false
+
+ # Allow datasets in rules write access for "save" and
+ # "state". This is enabled by default, however write access is
+ # limited to the data directory.
+ allow-write: true
+
+By setting ``datasets.rules.allow-write`` to false, all ``save`` and
+``state`` rules will fail to load. This option is enabled by default
+to preserve compatiblity with previous 6.0 Suricata releases, however
+may change in a future major release.
+
+Pre-Suricata 6.0.13 behavior can be restored by setting
+``datasets.rules.allow-absolute-filenames`` to ``true``, however
+allowing so will allow any rule to overwrite any file on your system
+that Suricata has write access to.
diff --git a/doc/userguide/rules/dcerpc-keywords.rst b/doc/userguide/rules/dcerpc-keywords.rst
new file mode 100644
index 0000000..2065f66
--- /dev/null
+++ b/doc/userguide/rules/dcerpc-keywords.rst
@@ -0,0 +1,71 @@
+DCERPC Keywords
+================
+
+Following keywords can be used for matching on fields in headers and payloads
+of DCERPC packets over UDP, TCP and SMB.
+
+dcerpc.iface
+-------------
+
+Match on the value of the interface UUID in a DCERPC header. If `any_frag` option
+is given, the match shall be done on all fragments. If it's not, the match shall
+only happen on the first fragment.
+
+The format of the keyword::
+
+ dcerpc.iface:<uuid>;
+ dcerpc.iface:<uuid>,[>,<,!,=]<iface_version>;
+ dcerpc.iface:<uuid>,any_frag;
+ dcerpc.iface:<uuid>,[>,<,!,=]<iface_version>,any_frag;
+
+Examples::
+
+ dcerpc.iface:367abb81-9844-35f1-ad32-98f038001003;
+ dcerpc.iface:367abb81-9844-35f1-ad32-98f038001003,!10;
+ dcerpc.iface:367abb81-9844-35f1-ad32-98f038001003,any_frag;
+ dcerpc.iface:367abb81-9844-35f1-ad32-98f038001003,>1,any_frag;
+
+ET Open rule example:
+
+.. container:: example-rule
+
+ alert tcp any any -> $HOME_NET any (msg:"ET NETBIOS DCERPC WMI Remote Process Execution"; flow:to_server,established; dce_iface:00000143-0000-0000-c000-000000000046; classtype:bad-unknown; sid:2027167; rev:1; metadata:affected_product Windows_XP_Vista_7_8_10_Server_32_64_Bit, attack_target Client_Endpoint, created_at 2019_04_09, deployment Internal, former_category NETBIOS, signature_severity Informational, updated_at 2019_04_09;)
+
+
+dcerpc.opnum
+-------------
+
+Match on one or many operation numbers and/or operation number range within the
+interface in a DCERPC header.
+
+The format of the keyword::
+
+ dcerpc.opnum:<u16>;
+ dcerpc.opnum:[>,<,!,=]<u16>;
+ dcerpc.opnum:<u16>,<u16>,<u16>....;
+ dcerpc.opnum:<u16>-<u16>;
+
+Examples::
+
+ dcerpc.opnum:15;
+ dcerpc.opnum:>10;
+ dcerpc.opnum:12,24,62,61;
+ dcerpc.opnum:12,18-24,5;
+ dcerpc.opnum:12-14,12,121,62-78;
+
+dcerpc.stub_data
+-----------------
+
+Match on the stub data in a given DCERPC packet. It is a 'sticky buffer'.
+
+Example::
+
+ dcerpc.stub_data; content:"123456";
+
+
+Additional information
+-----------------------
+
+More information on the protocol can be found here:
+
+* DCERPC: `<https://pubs.opengroup.org/onlinepubs/9629399/chap1.htm>`_
diff --git a/doc/userguide/rules/dhcp-keywords.rst b/doc/userguide/rules/dhcp-keywords.rst
new file mode 100644
index 0000000..05675a9
--- /dev/null
+++ b/doc/userguide/rules/dhcp-keywords.rst
@@ -0,0 +1,59 @@
+DHCP keywords
+=============
+
+dhcp.leasetime
+--------------
+
+DHCP lease time (integer).
+
+Syntax::
+
+ dhcp.leasetime:[op]<number>
+
+The time can be matched exactly, or compared using the _op_ setting::
+
+ dhcp.leasetime:3 # exactly 3
+ dhcp.leasetime:<3 # smaller than 3
+ dhcp.leasetime:>=2 # greater or equal than 2
+
+Signature example::
+
+ alert dhcp any any -> any any (msg:"small DHCP lease time (<3)"; dhcp.leasetime:<3; sid:1; rev:1;)
+
+dhcp.rebinding_time
+-------------------
+
+DHCP rebinding time (integer).
+
+Syntax::
+
+ dhcp.rebinding_time:[op]<number>
+
+The time can be matched exactly, or compared using the _op_ setting::
+
+ dhcp.rebinding_time:3 # exactly 3
+ dhcp.rebinding_time:<3 # smaller than 3
+ dhcp.rebinding_time:>=2 # greater or equal than 2
+
+Signature example::
+
+ alert dhcp any any -> any any (msg:"small DHCP rebinding time (<3)"; dhcp.rebinding_time:<3; sid:1; rev:1;)
+
+dhcp.renewal_time
+-----------------
+
+DHCP renewal time (integer).
+
+Syntax::
+
+ dhcp.renewal_time:[op]<number>
+
+The time can be matched exactly, or compared using the _op_ setting::
+
+ dhcp.renewal_time:3 # exactly 3
+ dhcp.renewal_time:<3 # smaller than 3
+ dhcp.renewal_time:>=2 # greater or equal than 2
+
+Signature example::
+
+ alert dhcp any any -> any any (msg:"small DHCP renewal time (<3)"; dhcp.renewal_time:<3; sid:1; rev:1;) \ No newline at end of file
diff --git a/doc/userguide/rules/differences-from-snort.rst b/doc/userguide/rules/differences-from-snort.rst
new file mode 100644
index 0000000..9ca145c
--- /dev/null
+++ b/doc/userguide/rules/differences-from-snort.rst
@@ -0,0 +1,705 @@
+======================
+Differences From Snort
+======================
+
+This document is intended to highlight the major differences between Suricata
+and Snort that apply to rules and rule writing.
+
+Where not specified, the statements below apply to Suricata. In general,
+references to Snort refer to the version 2.9 branch.
+
+Automatic Protocol Detection
+----------------------------
+
+- Suricata does automatic protocol detection of the following
+ application layer protocols:
+
+ - dcerpc
+ - dnp3
+ - dns
+ - http
+ - imap (detection only by default; no parsing)
+ - ftp
+ - modbus (disabled by default; minimalist probe parser; can lead to false positives)
+ - smb
+ - smb2 (disabled internally inside the engine)
+ - smtp
+ - ssh
+ - tls (SSLv2, SSLv3, TLSv1, TLSv1.1 and TLSv1.2)
+
+- In Suricata, protocol detection is port agnostic (in most cases). In
+ Snort, in order for the ``http_inspect`` and other preprocessors to be
+ applied to traffic, it has to be over a configured port.
+
+ - Some configurations for app-layer in the Suricata yaml can/do by default
+ specify specific destination ports (e.g. DNS)
+ - **You can look on 'any' port without worrying about the
+ performance impact that you would have to be concerned about with
+ Snort.**
+
+- If the traffic is detected as HTTP by Suricata, the ``http_*``
+ buffers are populated and can be used, regardless of port(s)
+ specified in the rule.
+
+- You don't have to check for the http protocol (i.e.
+ ``alert http ...``) to use the ``http_*`` buffers although it
+ is recommended.
+
+- If you are trying to detect legitimate (supported) application layer
+ protocol traffic and don't want to look on specific port(s), the rule
+ should be written as ``alert <protocol> ...`` with ``any`` in
+ place of the usual protocol port(s). For example, when you want to
+ detect HTTP traffic and don't want to limit detection to a particular
+ port or list of ports, the rules should be written as
+ ``alert http ...`` with ``any`` in place of
+ ``$HTTP_PORTS``.
+
+ - You can also use ``app-layer-protocol:<protocol>;`` inside the rule instead.
+
+ So, instead of this Snort rule::
+
+ alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS ...
+
+ Do this for Suricata::
+
+ alert http $HOME_NET -> $EXTERNAL_NET any ...
+
+ Or::
+
+ alert tcp $HOME_NET any -> $EXTERNAL_NET any (app-layer-protocol:http; ...
+
+``urilen`` Keyword
+------------------
+
+- Ranges given in the ``urilen`` keyword are inclusive for Snort
+ but not inclusive for Suricata.
+
+ Example: ``urilen:2<>10``
+
+ - Snort interprets this as, "the URI length must be **greater than
+ or equal to** 2, and **less than or equal to** 10".
+ - Suricata interprets this as "the URI length must be **greater
+ than** 2 and **less than** 10".
+
+ - There is a request to have Suricata behave like Snort in future
+ versions –
+ `https://redmine.openinfosecfoundation.org/issues/1416 <https://redmine.openinfosecfoundation.org/issues/1416>`_
+
+ - Currently on hold
+
+- By default, with *Suricata*, ``urilen`` applies to the
+ **normalized** buffer
+
+ - Use ``,raw`` for raw buffer
+ - e.g. ``urilen:>20,raw;``
+
+- By default, with *Snort*, ``urilen`` applies to the **raw**
+ buffer
+
+ - Use ``,norm`` for normalized buffer
+ - e.g. ``urilen:>20,norm;``
+
+``http_uri`` Buffer
+-------------------
+
+- In Snort, the ``http_uri`` buffer normalizes '+' characters
+ (0x2B) to spaces (0x20).
+
+ - Suricata can do this as well but you have to explicitly
+ set ``query-plusspace-decode: yes`` in the ``libhtp`` section of Suricata's yaml file.
+
+- `https://redmine.openinfosecfoundation.org/issues/1035 <https://redmine.openinfosecfoundation.org/issues/1035>`_
+- `https://github.com/inliniac/suricata/pull/620 <https://github.com/inliniac/suricata/pull/620>`_
+
+``http_header`` Buffer
+----------------------
+
+- In Snort, the ``http_header`` buffer includes the CRLF CRLF (0x0D
+ 0x0A 0x0D 0x0A) that separates the end of the last HTTP header from
+ the beginning of the HTTP body. Suricata includes a CRLF after the
+ last header in the ``http_header`` buffer but not an extra one
+ like Snort does. If you want to match the end of the buffer, use
+ either the ``http_raw_header`` buffer, a relative
+ ``isdataat`` (e.g. ``isdataat:!1,relative``) or a PCRE
+ (although PCRE will be worse on performance).
+
+- Suricata *will* include CRLF CRLF at the end of the ``http_raw_header``
+ buffer like Snort does.
+
+- Snort will include a *leading* CRLF in the ``http_header`` buffer of
+ *server responses* (but not client requests). Suricata does not have
+ the leading CRLF in the ``http_header`` buffer of the server response
+ or client request.
+
+- In the ``http_header`` buffer, Suricata will normalize HTTP header lines
+ such that there is a single space (0x20) after the colon (':') that
+ separates the header name from the header value; this single space
+ replaces zero or more whitespace characters (including tabs) that may be
+ present in the raw HTTP header line immediately after the colon. If the
+ extra whitespace (or lack thereof) is important for matching, use
+ the ``http_raw_header`` buffer instead of the ``http_header`` buffer.
+
+- Snort will also normalize superfluous whitespace between the header name
+ and header value like Suricata does but only if there is at least one space
+ character (0x20 only so not 0x90) immediately after the colon. This means
+ that, unlike Suricata, if there is no space (or if there is a tab)
+ immediately after the colon before the header value, the content of the
+ header line will remain unchanged in the ``http_header`` buffer.
+
+- When there are duplicate HTTP headers (referring to the header name
+ only, not the value), the normalized buffer (``http_header``)
+ will concatenate the values in the order seen (from top to
+ bottom), with a comma and space (", ") between each of them. If this
+ hinders detection, use the ``http_raw_header`` buffer instead.
+
+ Example request::
+
+ GET /test.html HTTP/1.1
+ Content-Length: 44
+ Accept: */*
+ Content-Length: 55
+
+ The Content-Length header line becomes this in the ``http_header`` buffer::
+
+ Content-Length: 44, 55
+
+- The HTTP 'Cookie' and 'Set-Cookie' headers are **NOT** included in
+ the ``http_header`` buffer; instead they are extracted and put into
+ their own buffer – ``http_cookie``. See the `http_cookie Buffer`_
+ section.
+
+- The HTTP 'Cookie' and 'Set-Cookie' headers **ARE** included in the
+ ``http_raw_header`` buffer so if you are trying to match on
+ something like particular header ordering involving (or not
+ involving) the HTTP Cookie headers, use the ``http_raw_header``
+ buffer.
+
+- If 'enable\_cookie' is set for Snort, the HTTP Cookie header names
+ and trailing CRLF (i.e. "Cookie: \\r\\n" and "Set-Cooke \\r\\n") are
+ kept in the ``http_header`` buffer. This is not the case for
+ Suricata which removes the entire "Cookie" or "Set-Cookie" line from
+ the ``http_header`` buffer.
+
+- Other HTTP headers that have their own buffer
+ (``http_user_agent``, ``http_host``) are not removed from the
+ ``http_header`` buffer like the Cookie headers are.
+
+- When inspecting server responses and ``file_data`` is used,
+ content matches in ``http_*`` buffers should come before
+ ``file_data`` unless you use ``pkt_data`` to reset the cursor
+ before matching in ``http_*`` buffers. Snort will not complain if
+ you use ``http_*`` buffers after ``file_data`` is set.
+
+``http_cookie`` Buffer
+----------------------
+
+- The ``http_cookie`` buffer will NOT include the header name,
+ colon, or leading whitespace. i.e. it will not include "Cookie: " or "Set-Cookie: ".
+
+- The ``http_cookie`` buffer does not include a CRLF (0x0D 0x0A) at
+ the end. If you want to match the end of the buffer, use a relative
+ ``isdataat`` or a PCRE (although PCRE will be worse on
+ performance).
+
+- There is no ``http_raw_cookie`` buffer in Suricata. Use
+ ``http_raw_header`` instead.
+
+- You do not have to configure anything special to use the
+ 'http\_cookie' buffer in Suricata. This is different from Snort
+ where you have to set ``enable_cookie`` in the
+ ``http_inspect_server`` preprocessor config in order to have the
+ ``http_cookie`` buffer treated separate from the
+ ``http_header`` buffer.
+
+- If Snort has 'enable\_cookie' set and multiple "Cookie" or
+ "Set-Cookie" headers are seen, it will concatenate them together
+ (with no separator between them) in the order seen from top to
+ bottom.
+
+- If a request contains multiple "Cookie" or "Set-Cookie" headers, the
+ values will be concatenated in the Suricata ``http_cookie``
+ buffer, in the order seen from top to bottom, with a comma and space
+ (", ") between each of them.
+
+ Example request::
+
+ GET /test.html HTTP/1.1
+ Cookie: monster
+ Accept: */*
+ Cookie: elmo
+
+ Suricata ``http_cookie`` buffer contents::
+
+ monster, elmo
+
+ Snort ``http_cookie`` buffer contents::
+
+ monsterelmo
+
+- Corresponding PCRE modifier: ``C`` (same as Snort)
+
+New HTTP keywords
+-----------------
+
+Suricata supports several HTTP keywords that Snort doesn't have.
+
+Examples are ``http_user_agent``, ``http_host`` and ``http_content_type``.
+
+See :doc:`http-keywords` for all HTTP keywords.
+
+
+``byte_extract`` Keyword
+------------------------
+
+- Suricata supports
+ ``byte_extract`` from ``http_*`` buffers, including
+ ``http_header`` which does not always work as expected in Snort.
+
+- In Suricata, variables extracted using ``byte_extract`` must be used
+ in the same buffer, otherwise they will have the value "0" (zero). Snort
+ does allow cross-buffer byte extraction and usage.
+
+- Be sure to always positively and negatively test Suricata rules that
+ use ``byte_extract`` and ``byte_test`` to verify that they
+ work as expected.
+
+
+``byte_jump`` Keyword
+---------------------
+
+- Suricata allows a variable name from ``byte_extract`` or
+ ``byte_math`` to be specified for the ``nbytes`` value. The
+ value of ``nbytes`` must adhere to the same constraints
+ as if it were supplied directly in the rule.
+
+
+``byte_math`` Keyword
+---------------------
+
+- Suricata accepts ``dce`` as an endian value or as a separate keyword.
+ ``endian dce`` or ``dce`` are equivalent.
+
+- Suricata's rule parser rejects rules that repeat keywords in a single
+ rule. E.g., ``byte_math: endian big, endian little``.
+
+- Suricata's rule parser accepts ``rvalue`` values of ``0`` to the maximum
+ uint32 value. Snort rejects ``rvalue`` values of ``0`` and requires
+ values to be between ``[1..max-uint32 value]``.
+
+- Suricata will never match if there's a zero divisor. Division by 0 is undefined.
+
+``byte_test`` Keyword
+---------------------
+
+- Suricata allows a variable name from ``byte_extract`` or ``byte_math``
+ to be specified for the ``nbytes`` value. The value of ``nbytes`` must adhere
+ to the same constraints as though a value was directly supplied by the rule.
+
+- Suricata allows a variable name from ``byte_extract`` to be specified for
+ the ``nbytes`` value. The value of ``nbytes`` must adhere to the same constraints
+ as if it were supplied directly in the rule.
+
+
+``isdataat`` Keyword
+--------------------
+
+- The ``rawbytes`` keyword is supported in the Suricata syntax but
+ doesn't actually do anything.
+
+- Absolute ``isdataat`` checks will succeed if the offset used is
+ **less than** the size of the inspection buffer. This is true for
+ Suricata and Snort.
+
+- For *relative* ``isdataat`` checks, there is a **1 byte difference**
+ in the way Snort and Suricata do the comparisons.
+
+ - Suricata will succeed if the relative offset is **less than or
+ equal to** the size of the inspection buffer. This is different
+ from absolute ``isdataat`` checks.
+ - Snort will succeed if the relative offset is **less than** the
+ size of the inspection buffer, just like absolute ``isdataat``
+ checks.
+ - Example - to check that there is no data in the inspection buffer
+ after the last content match:
+
+ - Snort: ``isdataat:!0,relative;``
+ - Suricata: ``isdataat:!1,relative;``
+
+- With Snort, the "inspection buffer" used when checking an
+ ``isdataat`` keyword is generally the packet/segment with some
+ exceptions:
+
+ - With PAF enabled the PDU is examined instead of the
+ packet/segment. When ``file_data`` or ``base64_data`` has
+ been set, it is those buffers (unless ``rawbytes`` is set).
+ - With some preprocessors - modbus, gtp, sip, dce2, and dnp3 - the
+ buffer can be particular portions of those protocols (unless
+ ``rawbytes`` is set).
+ - With some preprocessors - rpc\_decode, ftp\_telnet, smtp, and dnp3
+ - the buffer can be particular *decoded* portions of those
+ protocols (unless ``rawbytes`` is set).
+
+- With Suricata, the "inspection buffer" used when checking an absolute
+ ``isdataat`` keyword is the packet/segment if looking at a packet
+ (e.g. ``alert tcp-pkt...``) or the reassembled stream segments.
+
+- In Suricata, a *relative* ``isdataat`` keyword **will apply to the
+ buffer of the previous content match**. So if the previous content
+ match is a ``http_*`` buffer, the relative ``isdataat``
+ applies to that buffer, starting from the end of the previous content
+ match in that buffer. *Snort does not behave like this!*
+
+- For example, this Suricata rule looks for the string ".exe" at the
+ end of the URI; to do the same thing in the normalized URI buffer in
+ Snort you would have to use a PCRE – ``pcre:"/\x2Eexe$/U";``
+
+ ::
+
+ alert http $HOME_NET any -> $EXTERNAL_NET any (msg:".EXE File Download Request"; flow:established,to_server; content:"GET"; http_method; content:".exe"; http_uri; isdataat:!1,relative; priority:3; sid:18332111;)
+
+- If you are unclear about behavior in a particular instance, you are
+ encouraged to positively and negatively test your rules that use an
+ ``isdataat`` keyword.
+
+Relative PCRE
+-------------
+
+- You can do relative PCRE matches in normalized/special buffers with Suricata. Example::
+
+ content:".php?sign="; http_uri; pcre:"/^[a-zA-Z0-9]{8}$/UR";
+
+- With Snort you can't combine the "relative" PCRE option ('R') with other buffer options like normalized URI ('U') – you get a syntax error.
+
+``tls*`` Keywords
+------------------
+
+In addition to TLS protocol identification, Suricata supports the storing of
+certificates to disk, verifying the validity dates on certificates, matching
+against the calculated SHA1 fingerprint of certificates, and
+matching on certain TLS/SSL certificate fields including the following:
+
+- Negotiated TLS/SSL version.
+- Certificate Subject field.
+- Certificate Issuer field.
+- Certificate SNI Field
+
+For details see :doc:`tls-keywords`.
+
+``dns_query`` Keyword
+---------------------
+
+- Sets the detection pointer to the DNS query.
+
+- Works like ``file_data`` does ("sticky buffer") but for a DNS
+ request query.
+
+- Use ``pkt_data`` to reset the detection pointer to the beginning of
+ the packet payload.
+
+- See :doc:`dns-keywords` for details.
+
+IP Reputation and ``iprep`` Keyword
+-----------------------------------
+
+- Snort has the "reputation" preprocessor that can be used to define
+ whitelist and blacklist files of IPs which are used generate GID 136
+ alerts as well as block/drop/pass traffic from listed IPs depending
+ on how it is configured.
+
+- Suricata also has the concept of files with IPs in them but provides
+ the ability to assign them:
+
+ - Categories
+ - Reputation score
+
+- Suricata rules can leverage these IP lists with the ``iprep``
+ keyword that can be configured to match on:
+
+ - Direction
+ - Category
+ - Value (reputation score)
+
+- :doc:`../reputation/index`
+- :doc:`../reputation/ipreputation/ip-reputation-config`
+- :doc:`ip-reputation-rules`
+- :doc:`../reputation/ipreputation/ip-reputation-format`
+- `https://blog.inliniac.net/2012/11/21/ip-reputation-in-suricata/ <https://blog.inliniac.net/2012/11/21/ip-reputation-in-suricata/>`_
+
+Flowbits
+--------
+
+- Suricata fully supports the setting and checking of flowbits
+ (including the same flowbit) on the same packet/stream. Snort does
+ not always allow for this.
+
+- In Suricata, ``flowbits:isset`` is checked after the fast pattern
+ match but before other ``content`` matches. In Snort,
+ ``flowbits:isset`` is checked in the order it appears in the
+ rule, from left to right.
+
+- If there is a chain of flowbits where multiple rules set flowbits and
+ they are dependent on each other, then the order of the rules or the
+ ``sid`` values can make a
+ difference in the rules being evaluated in the proper order and
+ generating alerts as expected. See bug 1399 -
+ `https://redmine.openinfosecfoundation.org/issues/1399 <https://redmine.openinfosecfoundation.org/issues/1399>`_.
+
+- :doc:`flow-keywords`
+
+flowbits:noalert;
+-----------------
+
+A common pattern in existing rules is to use ``flowbits:noalert;`` to make
+sure a rule doesn't generate an alert if it matches.
+
+Suricata allows using just ``noalert;`` as well. Both have an identical meaning
+in Suricata.
+
+Negated Content Match Special Case
+----------------------------------
+
+- For Snort, a *negated* content match where the starting point for
+ searching is at or beyond the end of the inspection buffer will never
+ return true.
+
+ - For negated matches, you want it to return true if the content is
+ not found.
+ - This is believed to be a Snort bug rather than an engine difference
+ but it was reported to Sourcefire and acknowledged many years ago
+ indicating that perhaps it is by design.
+ - This is not the case for Suricata which behaves as
+ expected.
+
+ Example HTTP request::
+
+ POST /test.php HTTP/1.1
+ Content-Length: 9
+
+ user=suri
+
+ This rule snippet will never return true in Snort but will in
+ Suricata::
+
+ content:!"snort"; offset:10; http_client_body;
+
+File Extraction
+---------------
+
+- Suricata has the ability to match on files from FTP, HTTP and SMTP streams and
+ log them to disk.
+
+- Snort has the "file" preprocessor that can do something similar
+ but it is experimental, development of it
+ has been stagnant for years, and it is not something that should be used
+ in a production environment.
+
+- Files can be matched on using a number of keywords including:
+
+ - ``filename``
+ - ``fileext``
+ - ``filemagic``
+ - ``filesize``
+ - ``filemd5``
+ - ``filesha1``
+ - ``filesha256``
+ - ``filesize``
+ - See :doc:`file-keywords` for a full list.
+
+- The ``filestore`` keyword tells Suricata to save the file to
+ disk.
+
+- Extracted files are logged to disk with meta data that includes
+ things like timestamp, src/dst IP, protocol, src/dst port, HTTP URI,
+ HTTP Host, HTTP Referer, filename, file magic, md5sum, size, etc.
+
+- There are a number of configuration options and considerations (such
+ as stream reassembly depth and libhtp body-limit) that should be
+ understood if you want fully utilize file extraction in Suricata.
+
+- :doc:`file-keywords`
+- :doc:`../file-extraction/file-extraction`
+- `https://blog.inliniac.net/2011/11/29/file-extraction-in-suricata/ <https://blog.inliniac.net/2011/11/29/file-extraction-in-suricata/>`_
+- `https://blog.inliniac.net/2014/11/11/smtp-file-extraction-in-suricata/ <https://blog.inliniac.net/2014/11/11/smtp-file-extraction-in-suricata/>`_
+
+Lua Scripting
+-------------
+
+- Suricata has the ``lua`` (or ``luajit``) keyword which allows for a
+ rule to reference a Lua script that can access the packet, payload,
+ HTTP buffers, etc.
+- Provides powerful flexibility and capabilities that Snort does
+ not have.
+- More details in: :ref:`lua-detection`
+
+Fast Pattern
+------------
+
+- Snort's fast pattern matcher is always case insensitive; Suricata's
+ is case sensitive unless 'nocase' is set on the content match used by
+ the fast pattern matcher.
+
+- Snort will truncate fast pattern matches based on the
+ ``max-pattern-len`` config (default no limit) unless
+ ``fast_pattern:only`` is used in the rule. Suricata does not do any
+ automatic fast pattern truncation cannot be configured to do so.
+
+- Just like in Snort, in Suricata you can specify a substring of the
+ content string to be use as the fast pattern match. e.g.
+ ``fast_pattern:5,20;``
+
+- In Snort, leading NULL bytes (0x00) will be removed from content
+ matches when determining/using the longest content match unless
+ ``fast_pattern`` is explicitly set. Suricata does not truncate
+ anything, including NULL bytes.
+
+- Snort does not allow for all ``http_*`` buffers to be used for
+ the fast pattern match (e.g. ``http_raw_*``, ``http_method``,
+ ``http_cookie``, etc.). Suricata lets you use any 'http\_\*'
+ buffer you want for the fast pattern match, including
+ ``http_raw_*' and ``http_cookie`` buffers.
+
+- Suricata supports the ``fast_pattern:only`` syntax but
+ technically it is not really implemented; the ``only`` is
+ silently ignored when encountered in a rule. It is still recommended
+ that you use ``fast_pattern:only`` where appropriate in case this
+ gets implemented in the future and/or if the rule will be used by
+ Snort as well.
+
+- With Snort, unless ``fast_pattern`` is explicitly set, content
+ matches in normalized HTTP Inspect buffers (e.g. http content
+ modifiers such ``http_uri``, ``http_header``, etc.) take
+ precedence over non-HTTP Inspect content matches, even if they are
+ shorter. Suricata does the same thing and gives a higher 'priority'
+ (precedence) to ``http_*`` buffers (except for ``http_method``,
+ ``http_stat_code``, and ``http_stat_msg``).
+
+- See :doc:`fast-pattern-explained` for full details on how Suricata
+ automatically determines which content to use as the fast pattern match.
+
+- When in doubt about what is going to be use as the fast pattern match
+ by Suricata, set ``fast_pattern`` explicitly in the rule and/or
+ run Suricata with the ``--engine-analysis`` switch and view the
+ generated file (``rules_fast_pattern.txt``).
+
+- Like Snort, the fast pattern match is checked before ``flowbits``
+ in Suricata.
+
+- Using Hyperscan as the MPM matcher (``mpm-algo`` setting) for Suricata
+ can greatly improve performance, especially when it comes to fast pattern
+ matching. Hyperscan will also take into account depth and offset
+ when doing fast pattern matching, something the other algorithms and
+ Snort do not do.
+
+- :ref:`rules-keyword-fast_pattern`
+
+Don't Cross The Streams
+-----------------------
+
+Suricata will examine network traffic as individual packets and, in the
+case of TCP, as part of a (reassembled) stream. However, there are
+certain rule keywords that only apply to packets only (``dsize``,
+``flags``, ``ttl``) and certain ones that only apply to streams
+only (``http_*``) and you can't mix packet and stream keywords. Rules
+that use packet keywords will inspect individual packets only and
+rules that use stream keywords will inspect streams only. Snort is a
+little more forgiving when you mix these – for example, in Snort you can
+use ``dsize`` (a packet keyword) with ``http_*`` (stream
+keywords) and Snort will allow it although, because of ``dsize``, it
+will only apply detection to individual packets (unless PAF is enabled
+then it will apply it to the PDU).
+
+If ``dsize`` is in a rule that also looks for a stream-based
+application layer protocol (e.g. ``http``), Suricata will not match on
+the *first application layer packet* since ``dsize`` make Suricata
+evaluate the packet and protocol detection doesn't happen until after
+the protocol is checked for that packet; *subsequent* packets in that
+flow should have the application protocol set appropriately and will
+match rules using ``dsize`` and a stream-based application layer
+protocol.
+
+If you need to check sizes on a stream in a rule that uses a stream
+keyword, or in a rule looking for a stream-based application layer
+protocol, consider using the ``stream_size`` keyword and/or
+``isdataat``.
+
+Suricata also supports these protocol values being used in rules and
+Snort does not:
+
+- ``tcp-pkt`` – example:
+
+ - ``alert tcp-pkt ...``
+ - This tells Suricata to only apply the rule to TCP packets and not
+ the (reassembled) stream.
+
+- ``tcp-stream`` – example:
+
+ - ``alert tcp-stream ...``
+ - This tells Suricata to inspect the (reassembled) TCP stream only.
+
+Alerts
+------
+
+- In Snort, the number of alerts generated for a packet/stream can be
+ limited by the ``event_queue`` configuration.
+
+- Suricata has an internal hard-coded limit of 15 alerts per packet/stream (and
+ this cannot be configured); all rules that match on the traffic being
+ analyzed will fire up to that limit.
+
+- Sometimes Suricata will generate what appears to be two alerts for
+ the same TCP packet. This happens when Suricata evaluates the packet
+ by itself and as part of a (reassembled) stream.
+
+Buffer Reference Chart
+----------------------
+
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| Buffer | Snort 2.9.x | Suricata | PCRE | Can be used as | Suricata Fast |
+| | Support? | Support? | flag | Fast Pattern? | Pattern Priority |
+| | | | | | (lower number is |
+| | | | | | higher priority) |
++=======================+==========================================+===========================================+========+================+==================+
+| content (no modifier) | YES | YES | <none> | YES | 3 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| http_method | YES | YES | M | Suricata only | 3 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| http_stat_code | YES | YES | S | Suricata only | 3 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| http_stat_msg | YES | YES | Y | Suricata only | 3 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| uricontent | YES but deprecated, use http_uri instead | YES but deprecated, use http_uri instead | U | YES | 2 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| http_uri | YES | YES | U | YES | 2 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| http_raw_uri | YES | YES | I | Suricata only | 2 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| http_header | YES | YES | H | YES | 2 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| http_raw_header | YES | YES | D | Suricata only | 2 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| http_cookie | YES | YES | C | Suricata only | 2 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| http_raw_cookie | YES | NO (use http_raw_header instead) | K | NO | n/a |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| http_host | NO | YES | W | Suricata only | 2 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| http_raw_host | NO | YES | Z | Suricata only | 2 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| http_client_body | YES | YES | P | YES | 2 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| http_server_body | NO | YES | Q | Suricata only | 2 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| http_user_agent | NO | YES | V | Suricata only | 2 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| dns_query | NO | YES | n/a\* | Suricata only | 2 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| tls_sni | NO | YES | n/a\* | Suricata only | 2 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| tls_cert_issuer | NO | YES | n/a\* | Suricata only | 2 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| tls_cert_subject | NO | YES | n/a\* | Suricata only | 2 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+| file_data | YES | YES | n/a\* | YES | 2 |
++-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+
+
+\* Sticky buffer
diff --git a/doc/userguide/rules/dnp3-keywords.rst b/doc/userguide/rules/dnp3-keywords.rst
new file mode 100644
index 0000000..36f5afd
--- /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:<value>;
+
+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:<flag>{,<flag>...}
+
+
+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:<group>,<variation>
+
+Where <group> and <variation> 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 0000000..e62a25d
--- /dev/null
+++ b/doc/userguide/rules/dns-keywords.rst
@@ -0,0 +1,74 @@
+DNS Keywords
+============
+
+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.opcode
+----------
+
+This keyword matches on the **opcode** found in the DNS header flags.
+
+Syntax
+~~~~~~
+
+::
+
+ dns.opcode:[!]<number>
+
+Examples
+~~~~~~~~
+
+Match on DNS requests and responses with **opcode** 4::
+
+ dns.opcode:4;
+
+Match on DNS requests where the **opcode** is NOT 0::
+
+ dns.opcode:!0;
+
+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.
+
+.. note:: **dns.query** is equivalent to the older **dns_query**.
+
+Normalized Buffer
+~~~~~~~~~~~~~~~~~
+
+Buffer contains literal domain name
+
+- <length> values (as seen in a raw DNS request)
+ are literal '.' characters
+- no leading <length> value
+- No terminating NULL (0x00) byte (use a negated relative ``isdataat``
+ to match the end)
+
+Example DNS request for "mail.google.com" (for readability, hex
+values are encoded between pipes):
+
+DNS query on the wire (snippet)::
+
+ |04|mail|06|google|03|com|00|
+
+``dns.query`` buffer::
+
+ mail.google.com
+
+Multiple Buffer Matching
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+``dns.query`` supports multiple buffer matching, see :doc:`multi-buffer-matching`. \ No newline at end of file
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 0000000..35d16ca
--- /dev/null
+++ b/doc/userguide/rules/dns-keywords/dns_query.png
Binary files differ
diff --git a/doc/userguide/rules/enip-keyword.rst b/doc/userguide/rules/enip-keyword.rst
new file mode 100644
index 0000000..5899ca4
--- /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 separated 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:<value>
+ cip_service:<value(s)>
+ enip_command:<value>, cip_service:<value(s)>
+
+
+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:
+`<http://literature.rockwellautomation.com/idc/groups/literature/documents/wp/enet-wp001_-en-p.pdf>`_
diff --git a/doc/userguide/rules/fast-pattern-explained.rst b/doc/userguide/rules/fast-pattern-explained.rst
new file mode 100644
index 0000000..88f0f3b
--- /dev/null
+++ b/doc/userguide/rules/fast-pattern-explained.rst
@@ -0,0 +1,99 @@
+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 application layer buffers
+ have a higher priority (lower number is higher priority). The buffer
+ `http_method` is an exception and has lower priority than the general
+ `content` buffer.
+#. 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 A
+ <fast-pattern-explained-appendix-a>` 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.
+#. 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 - 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 pattern
+ *
+ * \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/fast_pattern.png b/doc/userguide/rules/fast-pattern/fast_pattern.png
new file mode 100644
index 0000000..97163a5
--- /dev/null
+++ b/doc/userguide/rules/fast-pattern/fast_pattern.png
Binary files differ
diff --git a/doc/userguide/rules/file-keywords.rst b/doc/userguide/rules/file-keywords.rst
new file mode 100644
index 0000000..c708ee7
--- /dev/null
+++ b/doc/userguide/rules/file-keywords.rst
@@ -0,0 +1,265 @@
+File Keywords
+=============
+
+Suricata comes with several rule keywords to match on various file
+properties. They depend on properly configured
+:doc:`../file-extraction/file-extraction`.
+
+file.data
+---------
+
+The ``file.data`` sticky buffer matches on contents of files that are
+seen in flows that Suricata evaluates. The various payload keywords can
+be used (e.g. ``startswith``, ``nocase`` and ``bsize``) with ``file.data``.
+
+Example::
+
+ alert smtp any any -> any any (msg:"smtp app layer file.data example"; \
+ file.data; content:"example file content"; sid:1; rev:1)
+
+ alert http any any -> any any (msg:"http app layer file.data example"; \
+ file.data; content:"example file content"; sid:2; rev:1)
+
+ alert http2 any any -> any any (msg:"http2 app layer file.data example"; \
+ file.data; content:"example file content"; sid:3; rev:1;)
+
+ alert nfs any any -> any any (msg:"nfs app layer file.data example"; \
+ file.data; content:" "; sid:5; rev:1)
+
+ alert ftp-data any any -> any any (msg:"ftp app layer file.data example"; \
+ file.data; content:"example file content"; sid:6; rev:1;)
+
+ alert tcp any any -> any any (msg:"tcp file.data example"; \
+ file.data; content:"example file content"; sid:4; rev:1)
+
+**Note** file_data is the legacy notation but can still be used.
+
+
+file.name
+---------
+
+``file.name`` is a sticky buffer that is used to look at filenames
+that are seen in flows that Suricata evaluates. The various payload
+keywords can be used (e.g. ``startswith``, ``nocase`` and ``bsize``)
+with ``file.name``.
+
+Example::
+
+ file.name; content:"examplefilename";
+
+``file.name`` supports multiple buffer matching, see :doc:`multi-buffer-matching`.
+
+**Note** ``filename`` can still be used. A notable difference between
+``file.name`` and ``filename`` is that ``filename`` assumes ``nocase``
+by default. In the example below the two signatures are considered
+the same.
+
+Example::
+
+ filename:"examplefilename";
+
+ file.name; content:"examplefilename"; nocase;
+
+fileext
+--------
+
+``fileext`` is used to look at individual file extensions that are
+seen in flows that Suricata evaluates.
+
+Example::
+
+ fileext:"pdf";
+
+**Note:** ``fileext`` does not allow partial matches. For example, if
+a PDF file (.pdf) is seen by a Suricata signature with
+fileext:"pd"; the signature will not produce an alert.
+
+**Note:** ``fileext`` assumes ``nocase`` by default. This means
+that a file with the extension .PDF will be seen the same as if
+the file had an extension of .pdf.
+
+**Note:** ``fileext`` and ``file.name`` can both be used to match on
+file extensions. In the example below the two signatures are
+considered the same.
+
+Example::
+
+ fileext:"pdf";
+
+ file.name; content:".pdf"; nocase; endswith;
+
+**Note**: While``fileeext`` and ``file.name`` can both be used
+to match on file extensions, ``file.name`` allows for partial
+matching on file extensions. The following would match on a file
+with the extension of .pd as well as .pdf.
+
+Example::
+
+ file.name; content:".pd";
+
+file.magic
+----------
+
+Matches on the information libmagic returns about a file.
+
+Example::
+
+ file.magic; content:"executable for MS Windows";
+
+**Note** ``filemagic`` can still be used. The only difference between
+``file.magic`` and ``file.magic`` is that ``filemagic`` assumes ``nocase``
+by default. In the example below the two signatures are considered
+the same.
+
+Example::
+
+ filemagic:"executable for MS Windows";
+
+ file.magic; content:"executable for MS Windows"; nocase;
+
+Note: Suricata currently uses its underlying operating systems
+version/implementation of libmagic. Different versions and
+implementations of libmagic do not return the same information.
+Additionally there are varying Suricata performance impacts
+based on the version and implementation of libmagic.
+Additional information about Suricata and libmagic can be found
+here: https://redmine.openinfosecfoundation.org/issues/437
+
+``file.magic`` supports multiple buffer matching, see :doc:`multi-buffer-matching`.
+
+filestore
+---------
+
+Stores files to disk if the signature matched.
+
+Syntax::
+
+ filestore:<direction>,<scope>;
+
+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 <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: https://blog.inliniac.net/2012/06/09/suricata-md5-blacklisting/
+
+filesha1
+--------
+
+Match file SHA1 against list of SHA1 checksums.
+
+Syntax::
+
+ filesha1:[!]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::
+
+ filesha1:sha1-blacklist;
+ filesha1:!sha1-whitelist;
+
+*File format*
+
+Same as md5 file format.
+
+filesha256
+----------
+
+Match file SHA256 against list of SHA256 checksums.
+
+Syntax::
+
+ filesha256:[!]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::
+
+ filesha256:sha256-blacklist;
+ filesha256:!sha256-whitelist;
+
+*File format*
+
+Same as md5 file format.
+
+filesize
+--------
+
+Match on the size of the file as it is being transferred.
+
+Syntax::
+
+ filesize:<value>;
+
+Possible units are KB, MB and GB, without any unit the default is bytes.
+
+Examples::
+
+ filesize:100; # exactly 100 bytes
+ filesize:100<>200; # greater than 100 and smaller than 200
+ filesize:>100MB; # greater than 100 megabytes
+ filesize:<100MB; # smaller than 100 megabytes
+
+**Note**: For files that are not completely tracked because of packet
+loss or stream.reassembly.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 0000000..bb02692
--- /dev/null
+++ b/doc/userguide/rules/flow-keywords.rst
@@ -0,0 +1,308 @@
+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.
+
+It is also possible to perform an `OR` operation with flowbits with `|` op.
+
+Example::
+ alert http any any -> any any (msg: "User1 or User2 logged in"; content:"login"; flowbits:isset,user1|user2; sid:1;)
+
+This can be used with either `isset` or `isnotset` action.
+
+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 used 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 reassembled.
+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
+-------
+
+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: name, modifier[, value];
+
+Define a var (not required), or check that one is set or not set.
+
+::
+
+ flowint: name, < +,-,=,>,<,>=,<=,==, != >, value;
+ flowint: name, (isset|isnotset);
+
+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:"when flowint counter is 3 create new counter"; \
+ content:"Unauthorized"; flowint:myvar, isset; flowint:myvar,==,3; \
+ flowint:cntpackets,notset; flowint:cntpackets, =, 0;)
+
+::
+
+ alert tcp any any -> any any (msg:"count the rest without generating alerts"; \
+ flowint:cntpackets,isset; flowint:cntpackets, +, 1; noalert;)
+
+::
+
+ alert tcp any any -> any any (msg:"fire this when it reach 6"; \
+ flowint: cntpackets, isset; \
+ flowint: maxvar,isset; flowint: cntpackets, ==, maxvar;)
+
+
+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:<server|client|both|either>, <modifier>, <number>;
+
+Example of the stream-size keyword in a rule::
+
+ alert tcp any any -> any any (stream_size:both, >, 5000; sid:1;)
+
+flow.age
+--------
+
+Flow age in seconds (integer)
+
+Syntax::
+
+ flow.age: [op]<number>
+
+The time can be matched exactly, or compared using the _op_ setting::
+
+ flow.age:3 # exactly 3
+ flow.age:<3 # smaller than 3 seconds
+ flow.age:>=2 # greater or equal than 2 seconds
+
+Signature example::
+
+ alert tcp any any -> any any (msg:"Flow longer than one hour"; flow.age:>3600; flowbits: isnotset, onehourflow; flowbits: onehourflow, name; sid:1; rev:1;)
+
+In this example, we combine `flow.age` and `flowbits` to get an alert on the first packet after the flow's age is older than one hour. \ No newline at end of file
diff --git a/doc/userguide/rules/flow-keywords/Flow1.png b/doc/userguide/rules/flow-keywords/Flow1.png
new file mode 100644
index 0000000..8479a91
--- /dev/null
+++ b/doc/userguide/rules/flow-keywords/Flow1.png
Binary files differ
diff --git a/doc/userguide/rules/flow-keywords/Flow2.png b/doc/userguide/rules/flow-keywords/Flow2.png
new file mode 100644
index 0000000..b1cd6ae
--- /dev/null
+++ b/doc/userguide/rules/flow-keywords/Flow2.png
Binary files 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 0000000..4c9b835
--- /dev/null
+++ b/doc/userguide/rules/flow-keywords/Flowbit_3.png
Binary files differ
diff --git a/doc/userguide/rules/ftp-keywords.rst b/doc/userguide/rules/ftp-keywords.rst
new file mode 100644
index 0000000..068b14e
--- /dev/null
+++ b/doc/userguide/rules/ftp-keywords.rst
@@ -0,0 +1,31 @@
+FTP/FTP-DATA Keywords
+=====================
+
+ftpdata_command
+---------------
+
+Filter ftp-data channel based on command used on the FTP command channel.
+Currently supported commands are RETR (get on a file) and STOR (put on a
+file).
+
+Syntax::
+
+ ftpdata_command:(retr|stor)
+
+Examples::
+
+ ftpdata_command:retr
+ ftpdata_command:stor
+
+Signature example::
+
+ alert ftp-data any any -> any any (msg:"FTP store password"; filestore; filename:"password"; ftpdata_command:stor; sid:3; rev:1;)
+
+ftpbounce
+---------
+
+Detect FTP bounce attacks.
+
+Syntax::
+
+ ftpbounce
diff --git a/doc/userguide/rules/header-keywords.rst b/doc/userguide/rules/header-keywords.rst
new file mode 100644
index 0000000..36d1437
--- /dev/null
+++ b/doc/userguide/rules/header-keywords.rst
@@ -0,0 +1,732 @@
+.. role:: example-rule-emphasis
+
+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:<number>;
+
+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 from 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:
+
+.. container:: example-rule
+
+ alert ip $EXTERNAL_NET any -> $HOME_NET any (msg:"IP Packet With TTL 0";
+ :example-rule-emphasis:`ttl:0;` classtype:misc-activity; sid:1; rev:1;)
+
+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:
+
+========= =============================
+IP Option Description
+========= =============================
+rr Record Route
+eol End of List
+nop No Op
+ts Time Stamp
+sec IP Security
+esec IP Extended Security
+lsrr Loose Source Routing
+ssrr Strict Source Routing
+satid Stream Identifier
+any any IP options are set
+========= =============================
+
+Format of the ipopts keyword::
+
+ ipopts: <name>;
+
+For example::
+
+ ipopts: ts;
+
+Example of ipopts in a rule:
+
+.. container:: example-rule
+
+ alert ip $EXTERNAL_NET any -> $HOME_NET any (msg:"IP Packet with timestamp option"; :example-rule-emphasis:`ipopts:ts;` classtype:misc-activity; sid:2; rev:1;)
+
+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:
+
+.. container:: example-rule
+
+ alert ip any any -> any any (msg:"IP Packet with the same source and destination IP"; :example-rule-emphasis:`sameip;` classtype:bad-unknown; sid:3; rev:1;)
+
+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:
+
+.. container:: example-rule
+
+ alert ip any any -> any any (msg:"IP Packet with protocol 1"; :example-rule-emphasis:`ip_proto:1;` classtype:bad-unknown; sid:5; rev:1;)
+
+The named variant of that example would be::
+
+ ip_proto:ICMP;
+
+ipv4.hdr
+^^^^^^^^
+
+Sticky buffer to match on content contained within an IPv4 header.
+
+Example rule:
+
+.. container:: example-rule
+
+ alert ip any any -> any any (msg:"IPv4 header keyword example"; :example-rule-emphasis:`ipv4.hdr; content:"|06|"; offset:9; depth:1;` sid:1; rev:1;)
+
+This example looks if byte 10 of IPv4 header has value 06, which indicates that
+the IPv4 protocol is TCP.
+
+ipv6.hdr
+^^^^^^^^
+
+Sticky buffer to match on content contained within an IPv6 header.
+
+Example rule:
+
+.. container:: example-rule
+
+ alert ip any any -> any any (msg:"IPv6 header keyword example"; :example-rule-emphasis:`ipv6.hdr; content:"|06|"; offset:6; depth:1;` sid:1; rev:1;)
+
+This example looks if byte 7 of IP64 header has value 06, which indicates that
+the IPv6 protocol is TCP.
+
+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 used 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:<number>;
+
+Example of id in a rule:
+
+.. container:: example-rule
+
+ alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"id keyword example"; :example-rule-emphasis:`id:1;` content:"content|3a 20|"; fast_pattern; classtype:misc-activity; sid:12; rev:1;)
+
+geoip
+^^^^^
+The geoip keyword enables matching on the source, destination or
+source and destination IPv4 addresses of network traffic, and to see to
+which country it belongs. To be able to do this, Suricata uses the GeoIP2
+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;
+
+====== =============================================================
+Option Description
+====== =============================================================
+both Both source and destination have to match with the given geoip(s)
+any Either the source or the destination has to match with the given geoip(s).
+dest The destination matches with the given geoip.
+src The source matches with the given geoip.
+====== =============================================================
+
+geoip currently only supports IPv4. As it uses the GeoIP2 API of MaxMind,
+libmaxminddb must be compiled in. You must download and install the
+GeoIP2 or GeoLite2 database editions desired. Visit the MaxMind site
+at https://dev.maxmind.com/geoip/geolite2-free-geolocation-data for details.
+
+You must also supply the location of the GeoIP2 or GeoLite2 database
+file on the local system in the YAML-file configuration (for example)::
+
+ geoip-database: /usr/local/share/GeoIP/GeoLite2-Country.mmdb
+
+fragbits (IP fragmentation)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+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:
+
+.. container:: example-rule
+
+ alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"fragbits keyword example non-fragmented packet with fragment offset>0"; :example-rule-emphasis:`fragbits:M;` fragoffset:>0; classtype:bad-unknown; sid:123; rev:1;)
+
+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:[!|<|>]<number>;
+
+Example of fragoffset in a rule:
+
+.. container:: example-rule
+
+ alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"fragoffset keyword example invalid non-fragmented packet with fragment offset>0"; fragbits:M; :example-rule-emphasis:`fragoffset:>0;` classtype:bad-unknown; sid:13; rev:1;)
+
+tos
+^^^
+
+The tos keyword can match on specific decimal values of the IP header TOS
+field. The tos keyword can have a value from 0 - 255. This field of the
+IP header has been updated by `rfc2474 <https://tools.ietf.org/html/rfc2474>`_
+to include functionality for
+`Differentiated services <https://en.wikipedia.org/wiki/Differentiated_services>`_.
+Note that the value of the field has been defined with the right-most 2 bits having
+the value 0. When specifying a value for tos, ensure that the value follows this.
+
+E.g, instead of specifying the decimal value 34 (hex 22), right shift twice and use
+decimal 136 (hex 88).
+
+You can specify hexadecimal values with a leading `x`, e.g, `x88`.
+
+Format of tos::
+
+ tos:[!]<number>;
+
+Example of tos in a rule:
+
+.. container:: example-rule
+
+ alert ip any any -> any any (msg:"tos keyword example tos value 8"; flow:established; :example-rule-emphasis:`tos:8;` classtype:not-suspicious; sid:123; rev:1;)
+
+Example of tos with a negated value:
+
+.. container:: example-rule
+
+ alert ip any any -> any any (msg:"tos keyword example with negated content"; flow:established,to_server; :example-rule-emphasis:`tos:!8;` classtype:bad-unknown; sid:14; rev:1;)
+
+
+TCP keywords
+------------
+
+tcp.flags
+^^^^^^^^^
+
+The tcp.flags keyword checks for specific `TCP flag bits
+<https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure>`_.
+
+The following flag bits may be checked:
+
+==== ====================================
+Flag Description
+==== ====================================
+F FIN - Finish
+S SYN - Synchronize sequence numbers
+R RST - Reset
+P PSH - Push
+A ACK - Acknowledgment
+U URG - Urgent
+C CWR - Congestion Window Reduced
+E ECE - ECN-Echo
+0 No TCP Flags Set
+==== ====================================
+
+The following modifiers can be set to change the match criteria:
+
+======== ===================================
+Modifier Description
+======== ===================================
+``+`` match on the bits, plus any others
+``*`` match if any of the bits are set
+``!`` match if the bits are not set
+======== ===================================
+
+To handle writing rules for session initiation packets such as ECN where a SYN
+packet is sent with CWR and ECE flags set, an option mask may be used by
+appending a comma and masked values. For example, a rule that checks for a SYN
+flag, regardless of the values of the reserved bits is ``tcp.flags:S,CE;``
+
+Format of tcp.flags::
+
+ tcp.flags:[modifier]<test flags>[,<ignore flags>];
+ tcp.flags:[!|*|+]<FSRPAUCE0>[,<FSRPAUCE>];
+
+Example::
+
+ alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"Example tcp.flags sig"; \
+ :example-rule-emphasis:`tcp.flags:FPU,CE;` classtype:misc-activity; sid:1; rev:1;)
+
+It is also possible to use the `tcp.flags` content as a fast_pattern by using the `prefilter` keyword. For more information on `prefilter` usage see :doc:`prefilter-keywords`
+
+Example::
+
+ alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"Example tcp.flags sig"; \
+ :example-rule-emphasis:`tcp.flags:FPU,CE; prefilter;` classtype:misc-activity; sid:1; rev:1;)
+
+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:
+
+.. container:: example-rule
+
+ alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"GPL SCAN NULL"; flow:stateless; ack:0; flags:0; :example-rule-emphasis:`seq:0;` reference:arachnids,4; classtype:attempted-recon; sid:2100623; rev:7;)
+
+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:
+
+.. container:: example-rule
+
+ alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"GPL SCAN NULL"; flow:stateless; :example-rule-emphasis:`ack:0;` flags:0; seq:0; reference:arachnids,4; classtype:attempted-recon; sid:2100623; rev:7;)
+
+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:[!]<number>;
+
+Example of window in a rule:
+
+.. container:: example-rule
+
+ alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"GPL DELETED typot trojan traffic"; flow:stateless; flags:S,12; :example-rule-emphasis:`window:55808;` reference:mcafee,100406; classtype:trojan-activity; sid:2182; rev:8;)
+
+tcp.mss
+^^^^^^^
+
+Match on the TCP MSS option value. Will not match if the option is not
+present.
+
+The format of the keyword::
+
+ tcp.mss:<min>-<max>;
+ tcp.mss:[<|>]<number>;
+ tcp.mss:<value>;
+
+Example rule:
+
+.. container:: example-rule
+
+ alert tcp $EXTERNAL_NET any -> $HOME_NET any (flow:stateless; flags:S,12; :example-rule-emphasis:`tcp.mss:<536;` sid:1234; rev:5;)
+
+tcp.hdr
+^^^^^^^
+
+Sticky buffer to match on the whole TCP header.
+
+Example rule:
+
+.. container:: example-rule
+
+ alert tcp $EXTERNAL_NET any -> $HOME_NET any (flags:S,12; :example-rule-emphasis:`tcp.hdr; content:"|02 04|"; offset:20; byte_test:2,<,536,0,big,relative;` sid:1234; rev:5;)
+
+This example starts looking after the fixed portion of the header, so
+into the variable sized options. There it will look for the MSS option
+(type 2, option len 4) and using a byte_test determine if the value of
+the option is lower than 536. The `tcp.mss` option will be more efficient,
+so this keyword is meant to be used in cases where no specific keyword
+is available.
+
+UDP keywords
+------------
+
+udp.hdr
+^^^^^^^
+
+Sticky buffer to match on the whole UDP header.
+
+Example rule:
+
+.. container:: example-rule
+
+ alert udp any any -> any any (:example-rule-emphasis:`udp.hdr; content:"|00 08|"; offset:4; depth:2;` sid:1234; rev:5;)
+
+This example matches on the length field of the UDP header. In this
+case the length of 8 means that there is no payload. This can also
+be matched using `dsize:0;`.
+
+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:[<|>]<number>;
+
+Example
+This example looks for an ICMP type greater than 10::
+
+ itype:>10;
+
+Example of the itype keyword in a signature:
+
+.. container:: example-rule
+
+ alert icmp $EXTERNAL_NET any -> $HOME_NET any (msg:"GPL SCAN Broadscan Smurf Scanner"; dsize:4; icmp_id:0; icmp_seq:0; :example-rule-emphasis:`itype:8;` classtype:attempted-recon; sid:2100478; rev:4;)
+
+The following lists all ICMP types known at the time of writing. A recent table can be found `at the website of IANA <https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml>`_
+
+========= ==========================================================
+ICMP Type Name
+========= ==========================================================
+0 Echo Reply
+3 Destination Unreachable
+4 Source Quench
+5 Redirect
+6 Alternate Host Address
+8 Echo
+9 Router Advertisement
+10 Router Solicitation
+11 Time Exceeded
+12 Parameter Problem
+13 Timestamp
+14 Timestamp Reply
+15 Information Request
+16 Information Reply
+17 Address Mask Request
+18 Address Mask Reply
+30 Traceroute
+31 Datagram Conversion Error
+32 Mobile Host Redirect
+33 IPv6 Where-Are-You
+34 IPv6 I-Am-Here
+35 Mobile Registration Request
+36 Mobile Registration Reply
+37 Domain Name Request
+38 Domain Name Reply
+39 SKIP
+40 Photuris
+41 Experimental mobility protocols such as Seamoby
+========= ==========================================================
+
+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:[<|>]<number>;
+
+Example:
+This example looks for an ICMP code greater than 5::
+
+ icode:>5;
+
+Example of the icode keyword in a rule:
+
+.. container:: example-rule
+
+ alert icmp $HOME_NET any -> $EXTERNAL_NET any (msg:"GPL MISC Time-To-Live Exceeded in Transit"; :example-rule-emphasis:`icode:0;` itype:11; classtype:misc-activity; sid:2100449; rev:7;)
+
+The following lists the meaning of all ICMP types. When a code is not listed,
+only type 0 is defined and has the meaning of the ICMP code, in the table above.
+A recent table can be found `at the website of IANA <https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml>`_
+
++-----------+-----------+-----------------------------------------------------------------------+
+| ICMP Code | ICMP Type | Description |
++===========+===========+=======================================================================+
+| 3 | 0 | Net Unreachable |
+| +-----------+-----------------------------------------------------------------------+
+| | 1 | Host Unreachable |
+| +-----------+-----------------------------------------------------------------------+
+| | 2 | Protocol Unreachable |
+| +-----------+-----------------------------------------------------------------------+
+| | 3 | Port Unreachable |
+| +-----------+-----------------------------------------------------------------------+
+| | 4 | Fragmentation Needed and Don't Fragment was Set |
+| +-----------+-----------------------------------------------------------------------+
+| | 5 | Source Route Failed |
+| +-----------+-----------------------------------------------------------------------+
+| | 6 | Destination Network Unknown |
+| +-----------+-----------------------------------------------------------------------+
+| | 7 | Destination Host Unknown |
+| +-----------+-----------------------------------------------------------------------+
+| | 8 | Source Host Isolated |
+| +-----------+-----------------------------------------------------------------------+
+| | 9 | Communication with Destination Network is Administratively Prohibited |
+| +-----------+-----------------------------------------------------------------------+
+| | 10 | Communication with Destination Host is Administratively Prohibited |
+| +-----------+-----------------------------------------------------------------------+
+| | 11 | Destination Network Unreachable for Type of Service |
+| +-----------+-----------------------------------------------------------------------+
+| | 12 | Destination Host Unreachable for Type of Service |
+| +-----------+-----------------------------------------------------------------------+
+| | 13 | Communication Administratively Prohibited |
+| +-----------+-----------------------------------------------------------------------+
+| | 14 | Host Precedence Violation |
+| +-----------+-----------------------------------------------------------------------+
+| | 15 | Precedence cutoff in effect |
++-----------+-----------+-----------------------------------------------------------------------+
+| 5 | 0 | Redirect Datagram for the Network (or subnet) |
+| +-----------+-----------------------------------------------------------------------+
+| | 1 | Redirect Datagram for the Host |
+| +-----------+-----------------------------------------------------------------------+
+| | 2 | Redirect Datagram for the Type of Service and Network |
+| +-----------+-----------------------------------------------------------------------+
+| | 3 | Redirect Datagram for the Type of Service and Host |
++-----------+-----------+-----------------------------------------------------------------------+
+| 9 | 0 | Normal router advertisement |
+| +-----------+-----------------------------------------------------------------------+
+| | 16 | Doesn't route common traffic |
++-----------+-----------+-----------------------------------------------------------------------+
+| 11 | 0 | Time to Live exceeded in Transit |
+| +-----------+-----------------------------------------------------------------------+
+| | 1 | Fragment Reassembly Time Exceeded |
++-----------+-----------+-----------------------------------------------------------------------+
+| 12 | 0 | Pointer indicates the error |
+| +-----------+-----------------------------------------------------------------------+
+| | 1 | Missing a Required Option |
+| +-----------+-----------------------------------------------------------------------+
+| | 2 | Bad Length |
++-----------+-----------+-----------------------------------------------------------------------+
+| 40 | 0 | Bad SPI |
+| +-----------+-----------------------------------------------------------------------+
+| | 1 | Authentication Failed |
+| +-----------+-----------------------------------------------------------------------+
+| | 2 | Decompression Failed |
+| +-----------+-----------------------------------------------------------------------+
+| | 3 | Decryption Failed |
+| +-----------+-----------------------------------------------------------------------+
+| | 4 | Need Authentication |
+| +-----------+-----------------------------------------------------------------------+
+| | 5 | Need Authorization |
++-----------+-----------+-----------------------------------------------------------------------+
+
+
+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:<number>;
+
+Example:
+This example looks for an ICMP ID of 0::
+
+ icmp_id:0;
+
+Example of the icmp_id keyword in a rule:
+
+.. container:: example-rule
+
+ alert icmp $EXTERNAL_NET any -> $HOME_NET any (msg:"GPL SCAN Broadscan Smurf Scanner"; dsize:4; :example-rule-emphasis:`icmp_id:0;` icmp_seq:0; itype:8; classtype:attempted-recon; sid:2100478; rev:4;)
+
+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:<number>;
+
+Example:
+This example looks for an ICMP Sequence of 0::
+
+ icmp_seq:0;
+
+Example of icmp_seq in a rule:
+
+.. container:: example-rule
+
+ alert icmp $EXTERNAL_NET any -> $HOME_NET any (msg:"GPL SCAN Broadscan Smurf Scanner"; dsize:4; icmp_id:0; :example-rule-emphasis:`icmp_seq:0;` itype:8; classtype:attempted-recon; sid:2100478; rev:4;)
+
+icmpv4.hdr
+^^^^^^^^^^
+
+Sticky buffer to match on the whole ICMPv4 header.
+
+icmpv6.hdr
+^^^^^^^^^^
+
+Sticky buffer to match on the whole ICMPv6 header.
+
+icmpv6.mtu
+^^^^^^^^^^
+
+Match on the ICMPv6 MTU optional value. Will not match if the MTU is not
+present.
+
+The format of the keyword::
+
+ icmpv6.mtu:<min>-<max>;
+ icmpv6.mtu:[<|>]<number>;
+ icmpv6.mtu:<value>;
+
+Example rule:
+
+.. container:: example-rule
+
+ alert ip $EXTERNAL_NET any -> $HOME_NET any (:example-rule-emphasis:`icmpv6.mtu:<1280;` sid:1234; rev:5;)
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 0000000..d90156b
--- /dev/null
+++ b/doc/userguide/rules/header-keywords/Wireshark_ack.png
Binary files 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 0000000..ac27163
--- /dev/null
+++ b/doc/userguide/rules/header-keywords/Wireshark_seq.png
Binary files differ
diff --git a/doc/userguide/rules/http-keywords.rst b/doc/userguide/rules/http-keywords.rst
new file mode 100644
index 0000000..0c0f652
--- /dev/null
+++ b/doc/userguide/rules/http-keywords.rst
@@ -0,0 +1,846 @@
+HTTP Keywords
+=============
+.. role:: example-rule-emphasis
+
+Using the HTTP specific sticky buffers provides a way to efficiently
+inspect specific fields of the HTTP protocol. After specifying a
+sticky buffer in a rule it should be followed by one or more :doc:`payload-keywords`.
+
+Many of the sticky buffers have legacy variants in the older "content modifier"
+notation. See :ref:`rules-modifiers` for more information. As a
+refresher:
+
+* **'sticky buffers'** are placed first and all keywords following it apply to that buffer, for instance::
+
+ alert http any any -> any any (http.response_line; content:"403 Forbidden"; sid:1;)
+
+ Sticky buffers apply to all "payload" keywords following it. E.g. `content`, `isdataat`, `byte_test`, `pcre`.
+
+* **'content modifiers'** look back in the rule, e.g.::
+
+ alert http any any -> any any (content:"index.php"; http_uri; sid:1;)
+
+ Content modifiers only apply to the preceding `content` keyword.
+
+The following **request** keywords are available:
+
+============================== ======================== ==================
+Keyword Legacy Content Modifier Direction
+============================== ======================== ==================
+http.uri http_uri Request
+http.uri.raw http_raw_uri Request
+http.method http_method Request
+http.request_line http_request_line (*) Request
+http.request_body http_client_body Request
+http.header http_header Both
+http.header.raw http_raw_header Both
+http.cookie http_cookie Both
+http.user_agent http_user_agent Request
+http.host http_host Request
+http.host.raw http_raw_host Request
+http.accept http_accept (*) Request
+http.accept_lang http_accept_lang (*) Request
+http.accept_enc http_accept_enc (*) Request
+http.referer http_referer (*) Request
+http.connection http_connection (*) Both
+file.data file_data (*) Both
+http.content_type http_content_type (*) Both
+http.content_len http_content_len (*) Both
+http.start http_start (*) Both
+http.protocol http_protocol (*) Both
+http.header_names http_header_names (*) Both
+============================== ======================== ==================
+
+\*) sticky buffer
+
+The following **response** keywords are available:
+
+============================== ======================== ==================
+Keyword Legacy Content Modifier Direction
+============================== ======================== ==================
+http.stat_msg http_stat_msg Response
+http.stat_code http_stat_code Response
+http.response_line http_response_line (*) Response
+http.header http_header Both
+http.header.raw http_raw_header Both
+http.cookie http_cookie Both
+http.response_body http_server_body Response
+http.server N/A Response
+http.location N/A Response
+file.data file_data (*) Both
+http.content_type http_content_type (*) Both
+http.content_len http_content_len (*) Both
+http.start http_start (*) Both
+http.protocol http_protocol (*) Both
+http.header_names http_header_names (*) Both
+============================== ======================== ==================
+
+\*) sticky buffer
+
+HTTP Primer
+-----------
+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 the 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.
+
+Example request with keywords:
+
++--------------------------------+------------------+
+| HTTP | Keyword |
++--------------------------------+------------------+
+| GET /index.html HTTP/1.1\\r\\n | http.request_line|
++--------------------------------+------------------+
+| Host: www.oisf.net\\r\\n | http.header |
++--------------------------------+------------------+
+| Cookie: **<cookie data>** | http.cookie |
++--------------------------------+------------------+
+
+Example request with finer grained keywords:
+
++------------------------------------------+---------------------+
+| HTTP | Keyword |
++------------------------------------------+---------------------+
+| **GET** */index.html* **HTTP/1.1**\\r\\n | **http.method** |
+| | *http.uri* |
+| | **http.protocol** |
++------------------------------------------+---------------------+
+| Host: **www.oisf.net**\\r\\n | **http.host** |
+| +---------------------+
+| User-Agent: **Mozilla/5.0**\\r\\n | **http.user_agent** |
++------------------------------------------+---------------------+
+| Cookie: **<cookie data>** | **http.cookie** |
++------------------------------------------+---------------------+
+
+**HTTP response**
+
+::
+
+ HTTP/1.0 200 OK\r\n
+ <html>
+ <title> some page </title>
+ </HTML>
+
+In this example, HTTP/1.0 is the HTTP version, 200 the response status
+code and OK the response status message.
+
+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`` sticky buffer, 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``.
+
+Examples of 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
+
+.. _rules-http-uri-normalization:
+
+http.uri and http.uri.raw
+-------------------------
+
+With the ``http.uri`` and the ``http.uri.raw`` sticky buffers, 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``.
+
+The uri has two appearances in Suricata: the uri.raw 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 uri.raw. The
+uri.raw and the normalized uri are separate buffers. So, the uri.raw
+inspects the uri.raw buffer and can not inspect the normalized buffer.
+
+.. note:: uri.raw never has any spaces in it.
+ With this request line ``GET /uid=0(root) gid=0(root) HTTP/1.1``,
+ the ``http.uri.raw`` will match ``/uid=0(root)``
+ and ``http.protocol`` will match ``gid=0(root) HTTP/1.1``
+ Reference: `https://redmine.openinfosecfoundation.org/issues/2881 <https://redmine.openinfosecfoundation.org/issues/2881>`_
+
+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
+
+uricontent
+----------
+
+The ``uricontent`` keyword has the exact same effect as the
+``http.uri`` sticky buffer. ``uricontent`` is a deprecated
+(although still supported) way to match specifically and only on the
+request URI buffer.
+
+Example of ``uricontent``:
+
+.. container:: example-rule
+
+ alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"ET TROJAN Possible Vundo Trojan Variant reporting to Controller"; flow:established,to_server; content:"POST "; depth:5; :example-rule-emphasis:`uricontent:"/frame.html?";` urilen: > 80; classtype:trojan-activity; reference:url,doc.emergingthreats.net/2009173; reference:url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/VIRUS/TROJAN_Vundo; sid:2009173; rev:2;)
+
+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 sticky buffer 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:
+
+.. container:: example-rule
+
+ alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"ET TROJAN Possible Vundo Trojan Variant reporting to Controller"; flow:established,to_server; content:"POST "; depth:5; uricontent:"/frame.html?"; :example-rule-emphasis:`urilen: > 80;` classtype:trojan-activity; reference:url,doc.emergingthreats.net/2009173; reference:url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/VIRUS/TROJAN_Vundo; sid:2009173; rev:2;)
+
+You can also append ``norm`` or ``raw`` to define what sort of buffer you want
+to use (normalized or raw buffer).
+
+http.protocol
+-------------
+
+The ``http.protocol`` inspects the protocol field from the HTTP request or
+response line. If the request line is 'GET / HTTP/1.0\r\n', then this buffer
+will contain 'HTTP/1.0'.
+
+Example::
+
+ alert http any any -> any any (flow:to_server; http.protocol; content:"HTTP/1.0"; sid:1;)
+
+``http.protocol`` replaces the previous keyword name: ```http_protocol``. You may continue to use the previous name, but it's recommended that rules be converted to use the new name.
+
+Example::
+
+ alert http any any -> any any (flow:to_server; http.protocol; content:"HTTP/1.0"; sid:1;)
+
+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.header.raw
+-------------------------------
+
+With the ``http.header`` sticky buffer, 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 sticky buffer (e.g. ``http.cookie``). The sticky buffer
+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:
+ https://lists.openinfosecfoundation.org/pipermail/oisf-users/2011-October/000935.html.
+ If there are multiple values for the same header name, they are
+ concatenated with a comma and space (", ") between each of them.
+ See RFC 2616 4.2 Message Headers.
+ To avoid that, use the ``http.header.raw`` 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`` sticky buffer it is possible to match
+specifically on the HTTP cookie contents. Keywords like ``depth``,
+``distance``, ``offset``, ``nocase`` and ``within`` can be used
+with ``http.cookie``.
+
+Note that cookies are passed in HTTP headers but Suricata extracts
+the cookie data to ``http.cookie`` and will not match cookie content
+put in the ``http.header`` sticky buffer.
+
+Example of a cookie in a HTTP request:
+
+Examples::
+
+ GET / HTTP/1.1
+ User-Agent: Mozilla/5.0
+ Host: www.example.com
+ Cookie: PHPSESSIONID=1234
+ Connection: close
+
+Example ``http.cookie`` keyword in a signature:
+
+.. container:: example-rule
+
+ alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"HTTP Request
+ with Cookie"; flow:established,to_server; http.method; content:"GET";
+ http.uri; content:"/"; fast_pattern; :example-rule-emphasis:`http.cookie;
+ content:"PHPSESSIONID="; startswith;` classtype:bad-unknown; sid:123;
+ rev:1;)
+
+http.user_agent
+---------------
+
+The ``http.user_agent`` sticky buffer 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.
+
+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
+
+Notes
+~~~~~
+
+- The ``http.user_agent`` buffer will NOT include the header name,
+ colon, or leading whitespace. i.e. it will not include
+ "User-Agent: ".
+
+- The ``http.user_agent`` buffer does not include a CRLF (0x0D
+ 0x0A) at the end. If you want to match the end of the buffer, use a
+ relative ``isdataat`` or a PCRE (although PCRE will be worse on
+ performance).
+
+- If a request contains multiple "User-Agent" headers, the values will
+ be concatenated in the ``http.user_agent`` buffer, in the order
+ seen from top to bottom, with a comma and space (", ") between each
+ of them.
+
+ Example request::
+
+ GET /test.html HTTP/1.1
+ User-Agent: SuriTester/0.8
+ User-Agent: GGGG
+
+ ``http.user_agent`` buffer contents::
+
+ SuriTester/0.8, GGGG
+
+- Corresponding PCRE modifier: ``V``
+
+- Using the ``http.user_agent`` buffer is more efficient when it
+ comes to performance than using the ``http.header`` buffer (~10%
+ better).
+
+- `https://blog.inliniac.net/2012/07/09/suricata-http\_user\_agent-vs-http\_header/ <https://blog.inliniac.net/2012/07/09/suricata-http_user_agent-vs-http_header/>`_
+
+http.accept
+-----------
+
+Sticky buffer to match on the HTTP Accept header. Only contains the header
+value. The \\r\\n after the header are not part of the buffer.
+
+Example::
+
+ alert http any any -> any any (http.accept; content:"image/gif"; sid:1;)
+
+http.accept_enc
+---------------
+
+Sticky buffer to match on the HTTP Accept-Encoding header. Only contains the
+header value. The \\r\\n after the header are not part of the buffer.
+
+Example::
+
+ alert http any any -> any any (http.accept_enc; content:"gzip"; sid:1;)
+
+
+http.accept_lang
+----------------
+
+Sticky buffer to match on the HTTP Accept-Language header. Only contains the
+header value. The \\r\\n after the header are not part of the buffer.
+
+Example::
+
+ alert http any any -> any any (http.accept_lang; content:"en-us"; sid:1;)
+
+
+http.connection
+---------------
+
+Sticky buffer to match on the HTTP Connection header. Only contains the
+header value. The \\r\\n after the header are not part of the buffer.
+
+Example::
+
+ alert http any any -> any any (http.connection; content:"keep-alive"; sid:1;)
+
+
+http.content_type
+-----------------
+
+Sticky buffer to match on the HTTP Content-Type headers. Only contains the
+header value. The \\r\\n after the header are not part of the buffer.
+
+Use flow:to_server or flow:to_client to force inspection of request or response.
+
+Examples::
+
+ alert http any any -> any any (flow:to_server; \
+ http.content_type; content:"x-www-form-urlencoded"; sid:1;)
+
+ alert http any any -> any any (flow:to_client; \
+ http.content_type; content:"text/javascript"; sid:2;)
+
+
+http.content_len
+----------------
+
+Sticky buffer to match on the HTTP Content-Length headers. Only contains the
+header value. The \\r\\n after the header are not part of the buffer.
+
+Use flow:to_server or flow:to_client to force inspection of request or response.
+
+Examples::
+
+ alert http any any -> any any (flow:to_server; \
+ http.content_len; content:"666"; sid:1;)
+
+ alert http any any -> any any (flow:to_client; \
+ http.content_len; content:"555"; sid:2;)
+
+To do a numeric inspection of the content length, ``byte_test`` can be used.
+
+Example, match if C-L is equal to or bigger than 8079::
+
+ alert http any any -> any any (flow:to_client; \
+ http.content_len; byte_test:0,>=,8079,0,string,dec; sid:3;)
+
+http.referer
+---------------
+
+Sticky buffer to match on the HTTP Referer header. Only contains the
+header value. The \\r\\n after the header are not part of the buffer.
+
+Example::
+
+ alert http any any -> any any (http.referer; content:".php"; sid:1;)
+
+http.start
+----------
+
+Inspect the start of a HTTP request or response. This will contain the
+request/response line plus the request/response headers. Use flow:to_server
+or flow:to_client to force inspection of request or response.
+
+Example::
+
+ alert http any any -> any any (http.start; content:"HTTP/1.1|0d 0a|User-Agent"; sid:1;)
+
+The buffer contains the normalized headers and is terminated by an extra
+\\r\\n to indicate the end of the headers.
+
+http.header_names
+-----------------
+
+Inspect a buffer only containing the names of the HTTP headers. Useful
+for making sure a header is not present or testing for a certain order
+of headers.
+
+Buffer starts with a \\r\\n and ends with an extra \\r\\n.
+
+Example buffer::
+
+ \\r\\nHost\\r\\n\\r\\n
+
+Example rule::
+
+ alert http any any -> any any (http.header_names; content:"|0d 0a|Host|0d 0a|"; sid:1;)
+
+Example to make sure *only* Host is present::
+
+ alert http any any -> any any (http.header_names; \
+ content:"|0d 0a|Host|0d 0a 0d 0a|"; sid:1;)
+
+Example to make sure *User-Agent* is directly after *Host*::
+
+ alert http any any -> any any (http.header_names; \
+ content:"|0d 0a|Host|0d 0a|User-Agent|0d 0a|"; sid:1;)
+
+Example to make sure *User-Agent* is after *Host*, but not necessarily directly after::
+
+ alert http any any -> any any (http.header_names; \
+ content:"|0d 0a|Host|0d 0a|"; content:"|0a 0d|User-Agent|0d 0a|"; \
+ distance:-2; sid:1;)
+
+http.request_body
+-----------------
+
+With the ``http.request_body`` sticky buffer, 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.request_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
+<suricata-yaml-configure-libhtp>` via the ``request-body-limit``
+setting.
+
+``http.request_body`` replaces the previous keyword name: ```http_client_body``. You may continue
++to use the previous name, but it's recommended that rules be converted to use
++the new name.
+
+http.stat_code
+--------------
+
+With the ``http.stat_code`` sticky buffer, 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`` sticky buffer, 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.response_body
+------------------
+
+With the ``http.response_body`` sticky buffer, 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
+<suricata-yaml-configure-libhtp>` via the ``response-body-limit``
+setting.
+
+Notes
+~~~~~
+
+- Using ``http.response_body`` is similar to having content matches
+ that come after ``file.data`` except that it doesn't permanently
+ (unless reset) set the detection pointer to the beginning of the
+ server response body. i.e. it is not a sticky buffer.
+
+- ``http.response_body`` will match on gzip decoded data just like
+ ``file.data`` does.
+
+- Since ``http.response_body`` matches on a server response, it
+ can't be used with the ``to_server`` or ``from_client`` flow
+ directives.
+
+- Corresponding PCRE modifier: ``Q``
+
+- further notes at the ``file.data`` section below.
+
+``http.response_body`` replaces the previous keyword name: ```http_server_body``. You may continue
++to use the previous name, but it's recommended that rules be converted to use
++the new name.
+
+http.server
+-----------
+
+Sticky buffer to match on the HTTP Server headers. Only contains the
+header value. The \\r\\n after the header are not part of the buffer.
+
+Example::
+
+ alert http any any -> any any (flow:to_client; \
+ http.server; content:"Microsoft-IIS/6.0"; sid:1;)
+
+http.location
+-------------
+
+Sticky buffer to match on the HTTP Location headers. Only contains the
+header value. The \\r\\n after the header are not part of the buffer.
+
+Example::
+
+ alert http any any -> any any (flow:to_client; \
+ http.location; content:"http://www.google.com"; sid:1;)
+
+
+http.host and http.host.raw
+---------------------------
+
+With the ``http.host`` sticky buffer, it is possible to
+match specifically and only the normalized hostname.
+The ``http.host.raw`` 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 is not allowed anymore. Keep in mind that you need
+to specify a lowercase pattern.
+
+http.request_header
+-------------------
+
+Match on the name and value of a HTTP request header (HTTP1 or HTTP2).
+
+For HTTP2, name and value get concatenated by ": ", colon and space.
+To detect if a http2 header name contains ':',
+the keyword ``http2.header_name`` can be used.
+
+Examples::
+
+ http.request_header; content:"agent: nghttp2";
+ http.request_header; content:"custom-header: I love::colons";
+
+``http.request_header`` is a 'sticky buffer'.
+
+``http.request_header`` can be used as ``fast_pattern``.
+
+
+http.response_header
+--------------------
+
+Match on the name and value of a HTTP response header (HTTP1 or HTTP2).
+
+For HTTP2, name and value get concatenated by ": ", colon and space.
+To detect if a http2 header name contains ':',
+the keyword ``http2.header_name`` can be used.
+
+Examples::
+
+ http.response_header; content:"server: nghttp2";
+ http.response_header; content:"custom-header: I love::colons";
+
+``http.response_header`` is a 'sticky buffer'.
+
+``http.response_header`` can be used as ``fast_pattern``.
+
+Notes
+~~~~~
+
+- ``http.host`` does not contain the port associated with
+ the host (i.e. abc.com:1234). To match on the host and port
+ or negate a host and port use ``http.host.raw``.
+
+- The ``http.host`` and ``http.host.raw`` buffers are populated
+ from either the URI (if the full URI is present in the request like
+ in a proxy request) or the HTTP Host header. If both are present, the
+ URI is used.
+
+- The ``http.host`` and ``http.host.raw`` buffers will NOT
+ include the header name, colon, or leading whitespace if populated
+ from the Host header. i.e. they will not include "Host: ".
+
+- The ``http.host`` and ``http.host.raw`` buffers do not
+ include a CRLF (0x0D 0x0A) at the end. If you want to match the end
+ of the buffer, use a relative 'isdataat' or a PCRE (although PCRE
+ will be worse on performance).
+
+- The ``http.host`` buffer is normalized to be all lower case.
+
+- The content match that ``http.host`` applies to must be all lower
+ case or have the ``nocase`` flag set.
+
+- ``http.host.raw`` matches the unnormalized buffer so matching
+ will be case-sensitive (unless ``nocase`` is set).
+
+- If a request contains multiple "Host" headers, the values will be
+ concatenated in the ``http.host`` and ``http.host.raw``
+ buffers, in the order seen from top to bottom, with a comma and space
+ (", ") between each of them.
+
+ Example request::
+
+ GET /test.html HTTP/1.1
+ Host: ABC.com
+ Accept: */*
+ Host: efg.net
+
+ ``http.host`` buffer contents::
+
+ abc.com, efg.net
+
+ ``http.host.raw`` buffer contents::
+
+ ABC.com, efg.net
+
+- Corresponding PCRE modifier (``http_host``): ``W``
+- Corresponding PCRE modifier (``http_raw_host``): ``Z``
+
+file.data
+---------
+
+With ``file.data``, the HTTP response body is inspected, just like
+with ``http.response_body``. The ``file.data`` keyword is a sticky buffer.
+``file.data`` also works for HTTP request body and can be used in other
+protocols than HTTP1.
+
+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.
+
+As the body of a HTTP response can be very large, it is inspected in
+smaller chunks.
+
+How much of the response/server body is inspected is controlled
+in your :ref:`libhtp configuration section
+<suricata-yaml-configure-libhtp>` via the ``response-body-limit``
+setting.
+
+If the HTTP body is a flash file compressed with 'deflate' or 'lzma',
+it can be decompressed and ``file.data`` can match on the decompress data.
+Flash decompression must be enabled under ``libhtp`` configuration:
+
+::
+
+ # Decompress SWF files.
+ # 2 types: 'deflate', 'lzma', 'both' will decompress deflate and lzma
+ # compress-depth:
+ # Specifies the maximum amount of data to decompress,
+ # set 0 for unlimited.
+ # decompress-depth:
+ # Specifies the maximum amount of decompressed data to obtain,
+ # set 0 for unlimited.
+ swf-decompression:
+ enabled: yes
+ type: both
+ compress-depth: 0
+ decompress-depth: 0
+
+Notes
+~~~~~
+
+- file.data is the preferred notation, however, file_data is still
+ recognized by the engine and works as well.
+
+- If a HTTP body is using gzip or deflate, ``file.data`` will match
+ on the decompressed data.
+
+- Negated matching is affected by the chunked inspection. E.g.
+ 'content:!"<html";' could not match on the first chunk, but would
+ then possibly match on the 2nd. To avoid this, use a depth setting.
+ The depth setting takes the body size into account.
+ Assuming that the ``response-body-minimal-inspect-size`` is bigger
+ than 1k, 'content:!"<html"; depth:1024;' can only match if the
+ pattern '<html' is absent from the first inspected chunk.
+
+- Refer to :doc:`file-keywords` for additional information.
+
+Multiple Buffer Matching
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+``file.data`` supports multiple buffer matching, see :doc:`multi-buffer-matching`. \ No newline at end of file
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 0000000..c3e9133
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/Legenda_rules.png
Binary files 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 0000000..d4ea6db
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/client_body.png
Binary files 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 0000000..5b9a749
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/client_body1.png
Binary files differ
diff --git a/doc/userguide/rules/http-keywords/cookie.png b/doc/userguide/rules/http-keywords/cookie.png
new file mode 100644
index 0000000..8e5c262
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/cookie.png
Binary files differ
diff --git a/doc/userguide/rules/http-keywords/cookie1.png b/doc/userguide/rules/http-keywords/cookie1.png
new file mode 100644
index 0000000..12293c3
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/cookie1.png
Binary files 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 0000000..97163a5
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/fast_pattern.png
Binary files 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 0000000..d604c07
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/file_data.png
Binary files differ
diff --git a/doc/userguide/rules/http-keywords/header.png b/doc/userguide/rules/http-keywords/header.png
new file mode 100644
index 0000000..d78714c
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/header.png
Binary files differ
diff --git a/doc/userguide/rules/http-keywords/header1.png b/doc/userguide/rules/http-keywords/header1.png
new file mode 100644
index 0000000..a255a0e
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/header1.png
Binary files 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 0000000..8fc84e1
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/http_server_body.png
Binary files 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 0000000..60a6786
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/http_uri.png
Binary files differ
diff --git a/doc/userguide/rules/http-keywords/method.png b/doc/userguide/rules/http-keywords/method.png
new file mode 100644
index 0000000..b718c8b
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/method.png
Binary files differ
diff --git a/doc/userguide/rules/http-keywords/method1.png b/doc/userguide/rules/http-keywords/method1.png
new file mode 100644
index 0000000..70d8c78
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/method1.png
Binary files differ
diff --git a/doc/userguide/rules/http-keywords/method2.png b/doc/userguide/rules/http-keywords/method2.png
new file mode 100644
index 0000000..1084618
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/method2.png
Binary files 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 0000000..77758ee
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/stat-code1.png
Binary files 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 0000000..a865fe1
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/stat_code.png
Binary files 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 0000000..f6f8ac8
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/stat_msg.png
Binary files 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 0000000..f26a075
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/stat_msg_1.png
Binary files differ
diff --git a/doc/userguide/rules/http-keywords/uri.png b/doc/userguide/rules/http-keywords/uri.png
new file mode 100644
index 0000000..e43b4f7
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/uri.png
Binary files differ
diff --git a/doc/userguide/rules/http-keywords/uri1.png b/doc/userguide/rules/http-keywords/uri1.png
new file mode 100644
index 0000000..d9fab6c
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/uri1.png
Binary files differ
diff --git a/doc/userguide/rules/http-keywords/uricontent1.png b/doc/userguide/rules/http-keywords/uricontent1.png
new file mode 100644
index 0000000..fa0cfac
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/uricontent1.png
Binary files differ
diff --git a/doc/userguide/rules/http-keywords/urilen.png b/doc/userguide/rules/http-keywords/urilen.png
new file mode 100644
index 0000000..1697db1
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/urilen.png
Binary files 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 0000000..f4fa2e8
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/user_agent.png
Binary files 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 0000000..d99d85b
--- /dev/null
+++ b/doc/userguide/rules/http-keywords/user_agent_match.png
Binary files differ
diff --git a/doc/userguide/rules/http2-keywords.rst b/doc/userguide/rules/http2-keywords.rst
new file mode 100644
index 0000000..1ad8355
--- /dev/null
+++ b/doc/userguide/rules/http2-keywords.rst
@@ -0,0 +1,118 @@
+HTTP2 Keywords
+==============
+
+HTTP2 frames are grouped into transactions based on the stream identifier it it is not 0.
+For frames with stream identifier 0, whose effects are global for the connection, a transaction is created for each frame.
+
+
+http2.frametype
+---------------
+
+Match on the frame type present in a transaction.
+
+Examples::
+
+ http2.frametype:GOAWAY;
+
+
+http2.errorcode
+---------------
+
+Match on the error code in a GOWAY or RST_STREAM frame
+
+Examples::
+
+ http2.errorcode: NO_ERROR;
+ http2.errorcode: INADEQUATE_SECURITY;
+
+
+http2.priority
+--------------
+
+Match on the value of the HTTP2 priority field present in a PRIORITY or HEADERS frame.
+
+This keyword takes a numeric argument after a colon and supports additional qualifiers, such as:
+
+* ``>`` (greater than)
+* ``<`` (less than)
+* ``x-y`` (range between values x and y)
+
+Examples::
+
+ http2.priority:2;
+ http2.priority:>100;
+ http2.priority:32-64;
+
+
+http2.window
+------------
+
+Match on the value of the HTTP2 value field present in a WINDOWUPDATE frame.
+
+This keyword takes a numeric argument after a colon and supports additional qualifiers, such as:
+
+* ``>`` (greater than)
+* ``<`` (less than)
+* ``x-y`` (range between values x and y)
+
+Examples::
+
+ http2.window:1;
+ http2.window:<100000;
+
+
+http2.size_update
+-----------------
+
+Match on the size of the HTTP2 Dynamic Headers Table.
+More information on the protocol can be found here:
+`<https://tools.ietf.org/html/rfc7541#section-6.3>`_
+
+This keyword takes a numeric argument after a colon and supports additional qualifiers, such as:
+
+* ``>`` (greater than)
+* ``<`` (less than)
+* ``x-y`` (range between values x and y)
+
+Examples::
+
+ http2.size_update:1234;
+ http2.size_update:>4096;
+
+
+http2.settings
+--------------
+
+Match on the name and value of a HTTP2 setting from a SETTINGS frame.
+
+This keyword takes a numeric argument after a colon and supports additional qualifiers, such as:
+
+* ``>`` (greater than)
+* ``<`` (less than)
+* ``x-y`` (range between values x and y)
+
+Examples::
+
+ http2.settings:SETTINGS_ENABLE_PUSH=0;
+ http2.settings:SETTINGS_HEADER_TABLE_SIZE>4096;
+
+http2.header_name
+-----------------
+
+Match on the name of a HTTP2 header from a HEADER frame (or PUSH_PROMISE or CONTINUATION).
+
+Examples::
+
+ http2.header_name; content:"agent";
+
+``http2.header_name`` is a 'sticky buffer'.
+
+``http2.header_name`` can be used as ``fast_pattern``.
+
+``http2.header_name`` supports multiple buffer matching, see :doc:`multi-buffer-matching`.
+
+Additional information
+----------------------
+
+More information on the protocol can be found here:
+`<https://tools.ietf.org/html/rfc7540>`_
diff --git a/doc/userguide/rules/ike-keywords.rst b/doc/userguide/rules/ike-keywords.rst
new file mode 100644
index 0000000..e0d9557
--- /dev/null
+++ b/doc/userguide/rules/ike-keywords.rst
@@ -0,0 +1,159 @@
+IKE Keywords
+============
+
+The keywords
+
+* ``ike.init_spi``
+* ``ike.resp_spi``
+* ``ike.chosen_sa_attribute``
+* ``ike.exchtype``
+* ``ike.vendor``
+* ``ike.key_exchange_payload``
+* ``ike.key_exchange_payload_length``
+* ``ike.nonce_payload``
+* ``ike.nonce_payload_length``
+
+can be used for matching on various properties of IKE connections.
+
+
+ike.init_spi, ike.resp_spi
+--------------------------
+
+Match on an exact value of the Security Parameter Index (SPI) for the Initiator or Responder.
+
+Examples::
+
+ ike.init_spi; content:"18fe9b731f9f8034";
+ ike.resp_spi; content:"a00b8ef0902bb8ec";
+
+``ike.init_spi`` and ``ike.resp_spi`` are 'sticky buffer'.
+
+``ike.init_spi`` and ``ike.resp_spi`` can be used as ``fast_pattern``.
+
+
+ike.chosen_sa_attribute
+-----------------------
+
+Match on an attribute value of the chosen Security Association (SA) by the Responder. Supported for IKEv1 are:
+``alg_enc``,
+``alg_hash``,
+``alg_auth``,
+``alg_dh``,
+``alg_prf``,
+``sa_group_type``,
+``sa_life_type``,
+``sa_life_duration``,
+``sa_key_length`` and
+``sa_field_size``.
+IKEv2 supports ``alg_enc``, ``alg_auth``, ``alg_prf`` and ``alg_dh``.
+
+If there is more than one chosen SA the event ``MultipleServerProposal`` is set. The attributes of the first SA are used for this keyword.
+
+
+Examples::
+
+ ike.chosen_sa_attribute:alg_hash=2;
+ ike.chosen_sa_attribute:sa_key_length=128;
+
+
+ike.exchtype
+------------
+
+Match on the value of the Exchange Type.
+
+This keyword takes a numeric argument after a colon and supports additional qualifiers, such as:
+
+* ``>`` (greater than)
+* ``<`` (less than)
+* ``>=`` (greater than or equal)
+* ``<=`` (less than or equal)
+* ``arg1-arg2`` (range)
+
+Examples::
+
+ ike.exchtype:5;
+ ike.exchtype:>=2;
+
+
+ike.vendor
+----------
+
+Match a vendor ID against the list of collected vendor IDs.
+
+Examples::
+
+ ike.vendor:4a131c81070358455c5728f20e95452f;
+
+``ike.vendor`` supports multiple buffer matching, see :doc:`multi-buffer-matching`.
+
+
+ike.key_exchange_payload
+------------------------
+
+Match against the public key exchange payload (e.g. Diffie-Hellman) of the server or client.
+
+Examples::
+
+ ike.key_exchange_payload; content:"|6d026d5616c45be05e5b898411e9|"
+
+``ike.key_exchange_payload`` is a 'sticky buffer'.
+
+``ike.key_exchange_payload`` can be used as ``fast_pattern``.
+
+
+ike.key_exchange_payload_length
+-------------------------------
+
+Match against the length of the public key exchange payload (e.g. Diffie-Hellman) of the server or client.
+
+This keyword takes a numeric argument after a colon and supports additional qualifiers, such as:
+
+* ``>`` (greater than)
+* ``<`` (less than)
+* ``>=`` (greater than or equal)
+* ``<=`` (less than or equal)
+* ``arg1-arg2`` (range)
+
+Examples::
+
+ ike.key_exchange_payload_length:>132
+
+
+ike.nonce_payload
+-----------------
+
+Match against the nonce of the server or client.
+
+Examples::
+
+ ike.nonce_payload; content:"|6d026d5616c45be05e5b898411e9|"
+
+``ike.nonce_payload`` is a 'sticky buffer'.
+
+``ike.nonce_payload`` can be used as ``fast_pattern``.
+
+
+ike.nonce_payload_length
+------------------------
+
+Match against the length of the nonce of the server or client.
+
+This keyword takes a numeric argument after a colon and supports additional qualifiers, such as:
+
+* ``>`` (greater than)
+* ``<`` (less than)
+* ``>=`` (greater than or equal)
+* ``<=`` (less than or equal)
+* ``arg1-arg2`` (range)
+
+Examples::
+
+ ike.nonce_payload_length:132
+ ike.nonce_payload_length:>132
+
+
+Additional information
+----------------------
+
+More information on the protocol and the data contained in it can be found here:
+`<https://tools.ietf.org/html/rfc2409>`_
diff --git a/doc/userguide/rules/index.rst b/doc/userguide/rules/index.rst
new file mode 100644
index 0000000..76266b3
--- /dev/null
+++ b/doc/userguide/rules/index.rst
@@ -0,0 +1,46 @@
+Suricata Rules
+==============
+
+.. toctree::
+
+ intro
+ meta
+ header-keywords
+ payload-keywords
+ transforms
+ prefilter-keywords
+ flow-keywords
+ bypass-keyword
+ http-keywords
+ file-keywords
+ dns-keywords
+ tls-keywords
+ ssh-keywords
+ ja3-keywords
+ modbus-keyword
+ dcerpc-keywords
+ dhcp-keywords
+ dnp3-keywords
+ enip-keyword
+ ftp-keywords
+ kerberos-keywords
+ smb-keywords
+ snmp-keywords
+ base64-keywords
+ sip-keywords
+ rfb-keywords
+ mqtt-keywords
+ ike-keywords
+ http2-keywords
+ quic-keywords
+ app-layer
+ xbits
+ thresholding
+ ip-reputation-rules
+ ipaddr
+ config
+ datasets
+ lua-detection
+ differences-from-snort
+ multi-buffer-matching
+ tag
diff --git a/doc/userguide/rules/intro.rst b/doc/userguide/rules/intro.rst
new file mode 100644
index 0000000..ab35f8a
--- /dev/null
+++ b/doc/userguide/rules/intro.rst
@@ -0,0 +1,319 @@
+Rules Format
+============
+
+Signatures play a very important role in Suricata. In most occasions
+people are using existing rulesets.
+
+The official way to install rulesets is described in :doc:`../rule-management/suricata-update`.
+
+There are a number of free rulesets that can be used via suricata-update.
+To aid in learning about writing rules, the Emerging Threats Open ruleset
+is free and a good reference that has a wide range of signature examples.
+
+This Suricata Rules document explains all about signatures; how to
+read, adjust and create them.
+
+A rule/signature consists of the following:
+
+* The **action**, determining what happens when the rule matches.
+* The **header**, defining the protocol, IP addresses, ports and direction of
+ the rule.
+* The **rule options**, defining the specifics of the rule.
+
+
+.. role:: example-rule-action
+.. role:: example-rule-header
+.. role:: example-rule-options
+.. role:: example-rule-emphasis
+
+An example of a rule is as follows:
+
+.. container:: example-rule
+
+ :example-rule-action:`alert` :example-rule-header:`http $HOME_NET any -> $EXTERNAL_NET any` :example-rule-options:`(msg:"HTTP GET Request Containing Rule in URI"; flow:established,to_server; http.method; content:"GET"; http.uri; content:"rule"; fast_pattern; classtype:bad-unknown; sid:123; rev:1;)`
+
+In this example, :example-rule-action:`red` is the action,
+:example-rule-header:`green` is the header and :example-rule-options:`blue`
+are the options.
+
+We will be using the above signature as an example throughout
+this section, highlighting the different parts of the signature.
+
+.. _actions:
+
+Action
+------
+.. container:: example-rule
+
+ :example-rule-emphasis:`alert` http $HOME_NET any -> $EXTERNAL_NET any (msg:"HTTP GET Request Containing Rule in URI"; flow:established,to_server; http.method; content:"GET"; http.uri; content:"rule"; fast_pattern; classtype:bad-unknown; sid:123; rev:1;)
+
+Valid actions are:
+
+* alert - generate an alert.
+* pass - stop further inspection of the packet.
+* drop - drop packet and generate alert.
+* reject - send RST/ICMP unreach error to the sender of the matching packet.
+* rejectsrc - same as just `reject`.
+* rejectdst - send RST/ICMP error packet to receiver of the matching packet.
+* rejectboth - send RST/ICMP error packets to both sides of the conversation.
+
+.. note:: In IPS mode, using any of the `reject` actions also enables `drop`.
+
+For more information see :ref:`suricata-yaml-action-order`.
+
+
+Protocol
+--------
+.. container:: example-rule
+
+ alert :example-rule-emphasis:`http` $HOME_NET any -> $EXTERNAL_NET any (msg:"HTTP GET Request Containing Rule in URI"; flow:established,to_server; http.method; content:"GET"; http.uri; content:"rule"; fast_pattern; classtype:bad-unknown; sid:123; rev:1;)
+
+This keyword in a signature tells Suricata which protocol it
+concerns. You can choose between four basic protocols:
+
+* tcp (for tcp-traffic)
+* udp
+* icmp
+* ip (ip stands for 'all' or 'any')
+
+There are a couple of additional TCP related protocol options:
+
+* tcp-pkt (for matching content in individual tcp packets)
+* tcp-stream (for matching content only in a reassembled tcp stream)
+
+There are also a few so-called application layer protocols, or layer 7 protocols
+you can pick from. These are:
+
+* http (either HTTP1 or HTTP2)
+* http1
+* http2
+* ftp
+* tls (this includes ssl)
+* smb
+* dns
+* dcerpc
+* dhcp
+* ssh
+* smtp
+* imap
+* modbus (disabled by default)
+* dnp3 (disabled by default)
+* enip (disabled by default)
+* nfs
+* ike
+* krb5
+* bittorrent-dht
+* ntp
+* dhcp
+* rfb
+* rdp
+* snmp
+* tftp
+* sip
+
+The availability of these protocols depends on whether the protocol
+is enabled in the configuration file, suricata.yaml.
+
+If you have a signature with the protocol declared as 'http', Suricata makes
+sure the signature will only match if the TCP stream contains http traffic.
+
+Source and destination
+----------------------
+.. container:: example-rule
+
+ alert http :example-rule-emphasis:`$HOME_NET` any -> :example-rule-emphasis:`$EXTERNAL_NET` any (msg:"HTTP GET Request Containing Rule in URI"; flow:established,to_server; http.method; content:"GET"; http.uri; content:"rule"; fast_pattern; classtype:bad-unknown; sid:123; rev:1;)
+
+*The first emphasized part is the traffic source, the second is the traffic destination (note the direction of the directional arrow).*
+
+With the source and destination, you specify the source of the traffic and the
+destination of the traffic, respectively. You can assign IP addresses,
+(both IPv4 and IPv6 are supported) and IP ranges. These can be combined with
+operators:
+
+============== =========================
+Operator Description
+============== =========================
+../.. IP ranges (CIDR notation)
+! exception/negation
+[.., ..] grouping
+============== =========================
+
+Normally, you would also make use of variables, such as ``$HOME_NET`` and
+``$EXTERNAL_NET``. The suricata.yaml configuration file specifies the IP addresses these
+concern. The respective ``$HOME_NET`` and ``$EXTERNAL_NET`` settings will be used in place of the variables in your rules.
+
+See :ref:`suricata-yaml-rule-vars` for more information.
+
+Rule usage examples:
+
+================================== ==========================================
+Example Meaning
+================================== ==========================================
+!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
+[..., [....]]
+[..., ![.....]]
+================================== ==========================================
+
+.. warning::
+
+ If you set your configuration to something like this::
+
+ HOME_NET: any
+ EXTERNAL_NET: !$HOME_NET
+
+ You cannot write a signature using ``$EXTERNAL_NET`` because it evaluates to
+ 'not any', which is an invalid value.
+
+.. note::
+
+ Please note that the source and destination address can also be matched via the ``ip.src`` and ``ip.dst`` keywords (See :ref:`ipaddr`). These
+ keywords are mostly used in conjunction with the dataset feature (:ref:`datasets`).
+
+Ports (source and destination)
+------------------------------
+.. container:: example-rule
+
+ alert http $HOME_NET :example-rule-emphasis:`any` -> $EXTERNAL_NET :example-rule-emphasis:`any` (msg:"HTTP GET Request Containing Rule in URI"; flow:established,to_server; http.method; content:"GET"; http.uri; content:"rule"; fast_pattern; classtype:bad-unknown; sid:123; rev:1;)
+
+*The first emphasized part is the source port, the second is the destination port (note the direction of the directional arrow).*
+
+Traffic comes in and goes out through ports. Different protocols have
+different port numbers. For example, the default port for HTTP is 80 while 443 is
+typically the port for HTTPS. Note, however, that the port does not
+dictate which protocol is used in the communication. Rather, it determines which
+application is receiving the data.
+
+The ports mentioned above are typically the destination ports. Source ports,
+i.e. the application that sent the packet, typically get assigned a random
+port by the operating system. When writing a rule for your own HTTP service,
+you would typically write ``any -> 80``, since that would mean any packet from
+any source port to your HTTP application (running on port 80) is matched.
+
+In setting ports you can make use of special operators as well. Operators such as:
+
+============== ==================
+Operator Description
+============== ==================
+: port ranges
+! exception/negation
+[.., ..] grouping
+============== ==================
+
+Rule usage examples:
+
+============== ==========================================
+Example Meaning
+============== ==========================================
+[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]] Range from 1-80, except ports 2 and 4
+[.., [..,..]]
+============== ==========================================
+
+
+Direction
+---------
+.. container:: example-rule
+
+ alert http $HOME_NET any :example-rule-emphasis:`->` $EXTERNAL_NET any (msg:"HTTP GET Request Containing Rule in URI"; flow:established,to_server; http.method; content:"GET"; http.uri; content:"rule"; fast_pattern; classtype:bad-unknown; sid:123; rev:1;)
+
+The directional arrow indicates which way the signature will be evaluated.
+In most signatures an arrow to the right (``->``) is used. This means that only
+packets with the same direction can match. However, it is also possible to
+have a rule match both directions (``<>``)::
+
+ source -> destination
+ source <> destination (both directions)
+
+The following example illustrates direction. In this example there is a client
+with IP address 1.2.3.4 using port 1024. A server with IP address 5.6.7.8,
+listening on port 80 (typically HTTP). The client sends a message to the server
+and the server replies with its answer.
+
+.. image:: intro/TCP-session.png
+
+Now, let's say we have a rule with the following header::
+
+ alert tcp 1.2.3.4 1024 -> 5.6.7.8 80
+
+Only the traffic from the client to the server will be matched by this rule,
+as the direction specifies that we do not want to evaluate the response packet.
+
+.. warning::
+
+ There is no 'reverse' style direction, i.e. there is no ``<-``.
+
+Rule options
+------------
+The rest of the rule consists of options. These are enclosed by parenthesis
+and separated by semicolons. Some options have settings (such as ``msg``),
+which are specified by the keyword of the option, followed by a colon,
+followed by the settings. Others have no settings; they are simply the
+keyword (such as ``nocase``)::
+
+ <keyword>: <settings>;
+ <keyword>;
+
+Rule options have a specific ordering and changing their order would change the
+meaning of the rule.
+
+.. 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\;";
+
+ As a consequence, you must also escape the backslash, as it functions
+ as an escape character.
+
+The rest of this chapter in the documentation documents the use of the various
+keywords.
+
+Some generic details about keywords follow.
+
+.. _rules-modifiers:
+
+Modifier Keywords
+~~~~~~~~~~~~~~~~~
+
+Some keywords function act as modifiers. There are two types of modifiers.
+
+* The older style **'content modifiers'** look back in the rule, e.g.::
+
+ 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, for instance::
+
+ 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.
+
+.. _rules-normalized-buffers:
+
+Normalized Buffers
+~~~~~~~~~~~~~~~~~~
+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':
+
+.. 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.
+
+Note that there are some exceptions, e.g. the ``http_raw_uri`` keyword.
+See :ref:`rules-http-uri-normalization` for more information.
diff --git a/doc/userguide/rules/intro/TCP-session.png b/doc/userguide/rules/intro/TCP-session.png
new file mode 100644
index 0000000..87d0eea
--- /dev/null
+++ b/doc/userguide/rules/intro/TCP-session.png
Binary files differ
diff --git a/doc/userguide/rules/ip-reputation-rules.rst b/doc/userguide/rules/ip-reputation-rules.rst
new file mode 100644
index 0000000..f0b5f18
--- /dev/null
+++ b/doc/userguide/rules/ip-reputation-rules.rst
@@ -0,0 +1,45 @@
+IP Reputation Keyword
+=====================
+
+IP Reputation can be used in rules through a new rule keyword "iprep".
+
+For more information about IP Reputation see :doc:`/reputation/ipreputation/ip-reputation-config` and :doc:`/reputation/ipreputation/ip-reputation-format`.
+
+iprep
+-----
+
+The iprep directive matches on the IP reputation information for a host.
+
+::
+
+ iprep:<side to check>,<category>,<operator>,<reputation score>
+
+
+side to check: <any|src|dst|both>
+
+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.
diff --git a/doc/userguide/rules/ipaddr.rst b/doc/userguide/rules/ipaddr.rst
new file mode 100644
index 0000000..c4e1953
--- /dev/null
+++ b/doc/userguide/rules/ipaddr.rst
@@ -0,0 +1,31 @@
+.. _ipaddr:
+
+IP Addresses Match
+==================
+
+Matching on IP addresses can be done via the IP tuple parameters or via the iprep keywords (see :doc:`/rules/ip-reputation-rules`).
+Some keywords providing interaction with datasets are also available.
+
+ip.src
+------
+
+The `ip.src` keyword is a sticky buffer to match on source IP address. It matches on the binary representation
+and is compatible with datasets of types `ip` and `ipv4`.
+
+Example:
+
+::
+
+ alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"Inbound bad list"; flow:to_server; ip.src; dataset:isset,badips,type ip,load badips.list; sid:1; rev:1;)
+
+ip.dst
+------
+
+The `ip.dst` keyword is a sticky buffer to match on destination IP address. It matches on the binary representation
+and is compatible with the dataset of type `ip` and `ipv4`.
+
+Example:
+
+::
+
+ alert tcp $HOME_NET any -> any any (msg:"Outbound bad list"; flow:to_server; ip.dst; dataset:isset,badips,type ip,load badips.list; sid:1; rev:1;)
diff --git a/doc/userguide/rules/ja3-keywords.rst b/doc/userguide/rules/ja3-keywords.rst
new file mode 100644
index 0000000..c77b9f3
--- /dev/null
+++ b/doc/userguide/rules/ja3-keywords.rst
@@ -0,0 +1,73 @@
+JA3 Keywords
+============
+
+Suricata comes with a JA3 integration (https://github.com/salesforce/ja3). JA3 is used to fingerprint TLS clients.
+
+JA3 must be enabled in the Suricata config file (set 'app-layer.protocols.tls.ja3-fingerprints' to 'yes').
+
+ja3.hash
+--------
+
+Match on JA3 hash (md5).
+
+Example::
+
+ alert tls any any -> any any (msg:"match JA3 hash"; \
+ ja3.hash; content:"e7eca2baf4458d095b7f45da28c16c34"; \
+ sid:100001;)
+
+``ja3.hash`` is a 'sticky buffer'.
+
+``ja3.hash`` can be used as ``fast_pattern``.
+
+``ja3.hash`` replaces the previous keyword name: ``ja3_hash``. You may continue
+to use the previous name, but it's recommended that rules be converted to use
+the new name.
+
+ja3.string
+----------
+
+Match on JA3 string.
+
+Example::
+
+ alert tls any any -> any any (msg:"match JA3 string"; \
+ ja3.string; content:"19-20-21-22"; \
+ sid:100002;)
+
+``ja3.string`` is a 'sticky buffer'.
+
+``ja3.string`` can be used as ``fast_pattern``.
+
+``ja3.string`` replaces the previous keyword name: ``ja3_string``. You may continue
+to use the previous name, but it's recommended that rules be converted to use
+the new name.
+
+ja3s.hash
+---------
+
+Match on JA3S hash (md5).
+
+Example::
+
+ alert tls any any -> any any (msg:"match JA3S hash"; \
+ ja3s.hash; content:"b26c652e0a402a24b5ca2a660e84f9d5"; \
+ sid:100003;)
+
+``ja3s.hash`` is a 'sticky buffer'.
+
+``ja3s.hash`` can be used as ``fast_pattern``.
+
+ja3s.string
+-----------
+
+Match on JA3S string.
+
+Example::
+
+ alert tls any any -> any any (msg:"match on JA3S string"; \
+ ja3s.string; content:"771,23-35"; sid:100004;)
+
+``ja3s.string`` is a 'sticky buffer'.
+
+``ja3s.string`` can be used as ``fast_pattern``.
diff --git a/doc/userguide/rules/kerberos-keywords.rst b/doc/userguide/rules/kerberos-keywords.rst
new file mode 100644
index 0000000..b005b1d
--- /dev/null
+++ b/doc/userguide/rules/kerberos-keywords.rst
@@ -0,0 +1,140 @@
+Kerberos Keywords
+=================
+
+krb5_msg_type
+-------------
+
+This keyword allows to match the Kerberos messages by its type (integer).
+It is possible to specify the following values defined in RFC4120:
+
+* 10 (AS-REQ)
+* 11 (AS-REP)
+* 12 (TGS-REQ)
+* 13 (TGS-REP)
+* 30 (ERROR)
+
+Syntax::
+
+ krb5_msg_type:<number>
+
+Signature examples::
+
+ alert krb5 any any -> any any (msg:"Kerberos 5 AS-REQ message"; krb5_msg_type:10; sid:3; rev:1;)
+ alert krb5 any any -> any any (msg:"Kerberos 5 AS-REP message"; krb5_msg_type:11; sid:4; rev:1;)
+ alert krb5 any any -> any any (msg:"Kerberos 5 TGS-REQ message"; krb5_msg_type:12; sid:5; rev:1;)
+ alert krb5 any any -> any any (msg:"Kerberos 5 TGS-REP message"; krb5_msg_type:13; sid:6; rev:1;)
+ alert krb5 any any -> any any (msg:"Kerberos 5 ERROR message"; krb5_msg_type:30; sid:7; rev:1;)
+
+
+.. note:: AP-REQ and AP-REP are not currently supported since those messages
+ are embedded in other application protocols.
+
+
+krb5_cname
+----------
+
+Kerberos client name, provided in the ticket (for AS-REQ and TGS-REQ messages).
+
+If the client name from the Kerberos message is composed of several parts, the
+name is compared to each part and the match will succeed if any is identical.
+
+Comparison is case-sensitive.
+
+Syntax::
+
+ krb5_cname; content:"name";
+
+Signature example::
+
+ alert krb5 any any -> any any (msg:"Kerberos 5 des server name"; krb5_cname; content:"des"; sid:4; rev:1;)
+
+``krb5_cname`` is a 'sticky buffer'.
+
+``krb5_cname`` can be used as ``fast_pattern``.
+
+``krb5.cname`` supports multiple buffer matching, see :doc:`multi-buffer-matching`.
+
+krb5_sname
+----------
+
+Kerberos server name, provided in the ticket (for AS-REQ and TGS-REQ messages)
+or in the error message.
+
+If the server name from the Kerberos message is composed of several parts, the
+name is compared to each part and the match will succeed if any is identical.
+
+Comparison is case-sensitive.
+
+Syntax::
+
+ krb5_sname; content:"name";
+
+Signature example::
+
+ alert krb5 any any -> any any (msg:"Kerberos 5 krbtgt server name"; krb5_sname; content:"krbtgt"; sid:5; rev:1;)
+
+``krb5_sname`` is a 'sticky buffer'.
+
+``krb5_sname`` can be used as ``fast_pattern``.
+
+``krb5.sname`` supports multiple buffer matching, see :doc:`multi-buffer-matching`.
+
+krb5_err_code
+-------------
+
+Kerberos error code (integer). This field is matched in Kerberos error messages only.
+
+For a list of error codes, refer to RFC4120 section 7.5.9.
+
+Syntax::
+
+ krb5_err_code:<number>
+
+Signature example::
+
+ alert krb5 any any -> any any (msg:"Kerberos 5 error C_PRINCIPAL_UNKNOWN"; krb5_err_code:6; sid:6; rev:1;)
+
+krb5.weak_encryption (event)
+----------------------------
+
+Event raised if the encryption parameters selected by the server are weak or
+deprecated. For example, using a key size smaller than 128, or using deprecated
+ciphers like DES.
+
+Syntax::
+
+ app-layer-event:krb5.weak_encryption
+
+Signature example::
+
+ alert krb5 any any -> any any (msg:"SURICATA Kerberos 5 weak encryption parameters"; flow:to_client; app-layer-event:krb5.weak_encryption; classtype:protocol-command-decode; sid:2226001; rev:1;)
+
+krb5.malformed_data (event)
+---------------------------
+
+Event raised in case of a protocol decoding error.
+
+Syntax::
+
+ app-layer-event:krb5.malformed_data
+
+Signature example::
+
+ alert krb5 any any -> any any (msg:"SURICATA Kerberos 5 malformed request data"; flow:to_server; app-layer-event:krb5.malformed_data; classtype:protocol-command-decode; sid:2226000; rev:1;)
+
+krb5.ticket_encryption
+----------------------
+
+Kerberos ticket encryption (enumeration).
+
+For a list of encryption types, refer to RFC3961 section 8.
+
+Syntax::
+
+ krb5.ticket_encryption: (!)"weak" or (space or comma)-separated list of integer or string values for an encryption type
+
+Signature example::
+
+ alert krb5 any any -> any any (krb5.ticket_encryption: weak; sid:1;)
+ alert krb5 any any -> any any (krb5.ticket_encryption: 23; sid:2;)
+ alert krb5 any any -> any any (krb5.ticket_encryption: rc4-hmac,rc4-hmac-exp; sid:3;) \ No newline at end of file
diff --git a/doc/userguide/rules/lua-detection.rst b/doc/userguide/rules/lua-detection.rst
new file mode 100644
index 0000000..80c926e
--- /dev/null
+++ b/doc/userguide/rules/lua-detection.rst
@@ -0,0 +1,104 @@
+.. _lua-detection:
+
+Lua Scripting for Detection
+===========================
+
+.. note:: Lua is disabled by default for use in rules, it must be
+ enabled in the configuration file. See the ``security.lua``
+ section of ``suricata.yaml`` and enable ``allow-rules``.
+
+Syntax:
+
+::
+
+ lua:[!]<scriptfilename>;
+
+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)
+* buffer -- the current sticky buffer
+* stream
+* dnp3
+* dns.request
+* dns.response
+* dns.rrname
+* ssh
+* smtp
+* tls
+* 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
+
+A comprehensive list of existing lua functions - with examples - can be found at :ref:`lua-functions` (some of them, however,
+work only for the lua-output functionality).
diff --git a/doc/userguide/rules/meta.rst b/doc/userguide/rules/meta.rst
new file mode 100644
index 0000000..1ceb5fe
--- /dev/null
+++ b/doc/userguide/rules/meta.rst
@@ -0,0 +1,261 @@
+Meta Keywords
+=============
+
+.. role:: example-rule-emphasis
+
+Meta keywords have no effect on Suricata's inspection of network traffic;
+they do have an effect on the way Suricata reports events/alerts.
+
+msg (message)
+-------------
+
+The keyword msg gives contextual information about the signature and the possible alert.
+
+The format of msg is::
+
+ msg: "some description";
+
+Examples::
+
+ msg:"ET MALWARE Win32/RecordBreaker CnC Checkin";
+ msg:"ET EXPLOIT SMB-DS DCERPC PnP bind attempt";
+
+To continue the example from the previous chapter, the msg component of the
+signature is emphasized below:
+
+.. container:: example-rule
+
+ alert http $HOME_NET any -> $EXTERNAL_NET any (:example-rule-emphasis:`msg:"HTTP GET Request Containing Rule in URI";` flow:established,to_server; http.method; content:"GET"; http.uri; content:"rule"; fast_pattern; classtype:bad-unknown; sid:123; rev:1;)
+
+.. tip::
+
+ It is a standard practice in rule writing to make the first part of the
+ signature msg uppercase and to indicate the class of the signature.
+
+ It is also standard practice that ``msg`` is the first keyword in the signature.
+
+.. 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
+greater than zero. The format of sid is::
+
+ sid:123;
+
+Example of sid in a signature:
+
+.. container:: example-rule
+
+ alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"HTTP GET Request Containing Rule in URI"; flow:established,to_server; http.method; content:"GET"; http.uri; content:"rule"; fast_pattern; classtype:bad-unknown; :example-rule-emphasis:`sid:123;` rev:1;)
+
+.. tip::
+
+ It is a standard practice in rule writing that the signature ``sid`` is
+ provided as the last keyword (or second-to-last if there is a ``rev``)
+ of the signature.
+
+ There are reserved ranges of sids, the reservations are recorded
+ at https://sidallocation.org/ .
+
+.. Note::
+
+ This value must be unique for all rules within the same :ref:`rule group
+ <gid>` (``gid``).
+
+ As Suricata-update currently considers the rule's ``sid`` only (cf. `Bug#5447
+ <https://redmine.openinfosecfoundation.org/issues/5447>`_), it is advisable
+ to opt for a completely unique ``sid`` altogether.
+
+rev (revision)
+--------------
+
+The sid keyword is commonly accompanied by the rev keyword. 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;
+
+
+Example of rev in a signature:
+
+.. container:: example-rule
+
+ alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"HTTP GET Request Containing Rule in URI"; flow:established,to_server; http.method; content:"GET"; http.uri; content:"rule"; fast_pattern; classtype:bad-unknown; sid:123; :example-rule-emphasis:`rev:1;`)
+
+.. tip::
+
+ It is a standard practice in rule writing that the rev keyword
+ is expressed after the sid keyword. The sid and rev keywords
+ are commonly put as the last two keywords in a signature.
+
+.. _gid:
+
+gid (group ID)
+--------------
+
+The gid keyword can be used to give different groups of
+signatures another id value (like in sid). Suricata by default uses gid 1.
+It is possible to modify the default value. In most cases, it will be
+unnecessary to change the default gid value. Changing the gid value
+has no technical implications, the value is only noted in alert data.
+
+Example of the gid value in an alert entry in the fast.log file.
+In the part [1:123], the first 1 is the gid (123 is the sid and 1 is the rev).
+
+.. container:: example-rule
+
+ 07/12/2022-21:59:26.713297 [**] [:example-rule-emphasis:`1`:123:1] HTTP GET Request Containing Rule in URI [**] [Classification: Potentially Bad Traffic] [Priority: 2] {TCP} 192.168.225.121:12407 -> 172.16.105.84:80
+
+
+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 CVE. For each classtype, the classification.config has a
+priority that will be used in the rule.
+
+Example classtype definition::
+
+ config classification: web-application-attack,Web Application Attack,1
+ config classification: not-suspicious,Not Suspicious Traffic,3
+
+Once we have defined the classification in the configuration file,
+we can use the classtypes in our rules. A rule with classtype web-application-attack
+will be assigned a priority of 1 and the alert will contain 'Web Application Attack'
+in the Suricata logs:
+
+======================= ====================== ===========
+classtype Alert Priority
+======================= ====================== ===========
+web-application-attack Web Application Attack 1
+not-suspicious Not Suspicious Traffic 3
+======================= ====================== ===========
+
+Our continuing example also has a classtype: bad-unknown:
+
+.. container:: example-rule
+
+ alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"HTTP GET Request Containing Rule in URI"; flow:established,to_server; http.method; content:"GET"; http.uri; content:"rule"; fast_pattern; :example-rule-emphasis:`classtype:bad-unknown;` sid:123; rev:1;)
+
+
+.. tip::
+
+ It is a standard practice in rule writing that the classtype keyword comes
+ before the sid and rev keywords (as shown in the example rule).
+
+reference
+---------
+The reference keyword is used to document 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:type,reference
+
+A typical reference to www.info.com would be::
+
+ reference:url,www.info.com
+
+There are several systems that can be used as a reference. A
+commonly known example is the CVE-database, which assigns numbers to
+vulnerabilities, to prevent having to type the same URL over and over
+again. An example reference of a CVE::
+
+ reference:cve,CVE-2014-1234
+
+This would make a reference to http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-1234.
+
+All the reference types are defined in the reference.config configuration file.
+
+priority
+--------
+
+The priority keyword comes with a mandatory numeric value which can
+range from 1 to 255. The values 1 through 4 are commonly used.
+The highest priority is 1. Signatures with a higher priority will
+be examined first. Normally signatures have a priority determined through
+a classtype definition. The classtype definition can be overridden
+by defining the priority keyword in the signature.
+The format of priority is::
+
+ priority:1;
+
+metadata
+--------
+The metadata keyword allows additional, non-functional, information to
+be added to the signature. While the format is free-form, it is
+recommended to stick to `[key, value]` pairs as Suricata can include these
+in eve alerts. The format is::
+
+ metadata: key value;
+ metadata: key value, key value;
+
+target
+------
+
+The target keyword allows the rules writer to specify which side of the
+alert is the target of the attack. If specified, the alert event is enhanced
+to contain information about source and target.
+
+The format is::
+
+ target:[src_ip|dest_ip]
+
+If the value is src_ip then the source IP in the generated event (src_ip
+field in JSON) is the target of the attack. If target is set to dest_ip
+then the target is the destination IP in the generated event.
+
+requires
+--------
+
+The ``requires`` keyword allows a rule to require specific Suricata
+features to be enabled, or the Suricata version to match an
+expression. Rules that do not meet the requirements will by ignored,
+and Suricata will not treat them as errors.
+
+When parsing rules, the parser attempts to process the ``requires``
+keywords before others. This allows it to occur after keywords that
+may only be present in specific versions of Suricata, as specified by
+the ``requires`` statement. However, the keywords preceding it must
+still adhere to the basic known formats of Suricata rules.
+
+The format is::
+
+ requires: feature geoip, version >= 7.0.0
+
+To require multiple features, the feature sub-keyword must be
+specified multiple times::
+
+ requires: feature geoip, feature lua
+
+Alternatively, *and* expressions may be expressed like::
+
+ requires: version >= 7.0.4 < 8
+
+and *or* expressions may expressed with ``|`` like::
+
+ requires: version >= 7.0.4 < 8 | >= 8.0.3
+
+to express that a rules requires version 7.0.4 or greater, but less
+than 8, **OR** greater than or equal to 8.0.3. Which could be useful
+if a keyword wasn't added until 7.0.4 and the 8.0.3 patch releases, as
+it would not exist in 8.0.1.
+
+This can be extended to multiple release branches::
+
+ requires: version >= 7.0.10 < 8 | >= 8.0.5 < 9 | >= 9.0.3
+
+If no *minor* or *patch* version component is provided, it will
+default to 0.
+
+The ``version`` may only be specified once, if specified more than
+once the rule will log an error and not be loaded.
+
+The ``requires`` keyword was introduced in Suricata 7.0.3 and 8.0.0.
diff --git a/doc/userguide/rules/modbus-keyword.rst b/doc/userguide/rules/modbus-keyword.rst
new file mode 100644
index 0000000..a485c71
--- /dev/null
+++ b/doc/userguide/rules/modbus-keyword.rst
@@ -0,0 +1,131 @@
+Modbus Keyword
+==============
+
+The modbus keyword can be used for matching on various properties of
+Modbus requests.
+
+There are three ways of using this keyword:
+
+* matching on functions properties with the setting "function";
+* matching on directly on data access with the setting "access";
+* matching on unit identifier with the setting "unit" only or with the previous setting "function" or "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 <value>
+ modbus: function <value>, subfunction <value>
+ modbus: function [!] <assigned | unassigned | public | user | reserved | all>
+
+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 <read | write>
+ modbus: access read <discretes | coils | input | holding>
+ modbus: access read <discretes | coils | input | holding>, address <value>
+ modbus: access write < coils | holding>
+ modbus: access write < coils | holding>, address <value>
+ modbus: access write < coils | holding>, address <value>, value <value>
+
+With _<value>_ 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 greater than 200 at address 500 of Holding Registers table
+
+With the setting **unit**, you can match on:
+
+* a MODBUS slave address of a remote device connected on the sub-network behind a bridge or a gateway. The destination IP address identifies the bridge itself and the bridge uses the MODBUS unit identifier to forward the request to the right slave device.
+
+Syntax::
+
+ modbus: unit <value>
+ modbus: unit <value>, function <value>
+ modbus: unit <value>, function <value>, subfunction <value>
+ modbus: unit <value>, function [!] <assigned | unassigned | public | user | reserved | all>
+ modbus: unit <value>, access <read | write>
+ modbus: unit <value>, access read <discretes | coils | input | holding>
+ modbus: unit <value>, access read <discretes | coils | input | holding>, address <value>
+ modbus: unit <value>, access write < coils | holding>
+ modbus: unit <value>, access write < coils | holding>, address <value>
+ modbus: unit <value>, access write < coils | holding>, address <value>, value <value>
+
+With _<value>_ setting matches on the address or value as it is being
+accessed or written as follows::
+
+ unit 10 # exactly unit identifier 10
+ unit 10<>20 # greater than unit identifier 10 and smaller than unit identifier 20
+ unit >10 # greater than unit identifier 10
+ unit <10 # smaller than unit identifier 10
+
+Examples::
+
+ modbus: unit 10 # Unit identifier 10
+ modbus: unit 10, function 21 # Unit identifier 10 and write File record function
+ modbus: unit 10, function 4, subfunction 4 # Unit identifier 10 and force Listen Only Mode (Diagnostics) function
+ modbus: unit 10, function assigned # Unit identifier 10 and assigned function
+ modbus: unit 10, function !reserved # Unit identifier 10 and every function but reserved function
+ modbus: unit 10, access read # Unit identifier 10 and Read access
+ modbus: unit 10, access write coils # Unit identifier 10 and Write access to Coils table
+ modbus: unit >10, access read discretes, address <100 # Greater than unit identifier 10 and Read access at address smaller than 100 of Discretes Input table
+ modbus: unit 10<>20, access write holding, address 500, value >200 # Greater than unit identifier 10 and smaller than unit identifier 20 and Write value greater 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)
+
+**Note:** According to MODBUS Messaging on TCP/IP Implementation Guide
+V1.0b, the MODBUS slave device addresses on serial line are assigned from 1 to
+247 (decimal). Address 0 is used as broadcast address.
+
+(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/mqtt-keywords.rst b/doc/userguide/rules/mqtt-keywords.rst
new file mode 100644
index 0000000..21776ac
--- /dev/null
+++ b/doc/userguide/rules/mqtt-keywords.rst
@@ -0,0 +1,264 @@
+MQTT Keywords
+=============
+
+Various keywords can be used for matching on fields in fixed and variable headers of MQTT messages as well as payload values.
+
+mqtt.protocol_version
+---------------------
+
+Match on the value of the MQTT protocol version field in the fixed header.
+
+The format of the keyword::
+
+ mqtt.protocol_version:<min>-<max>;
+ mqtt.protocol_version:[<|>]<number>;
+ mqtt.protocol_version:<value>;
+
+Examples:
+
+ mqtt.protocol_version:5;
+
+
+mqtt.type
+---------
+
+Match on the MQTT message type (also: control packet type).
+Valid values are :
+
+* ``CONNECT``
+* ``CONNACK``
+* ``PUBLISH``
+* ``PUBACK``
+* ``PUBREC``
+* ``PUBREL``
+* ``PUBCOMP``
+* ``SUBSCRIBE``
+* ``SUBACK``
+* ``UNSUBSCRIBE``
+* ``UNSUBACK``
+* ``PINGREQ``
+* ``PINGRESP``
+* ``DISCONNECT``
+* ``AUTH``
+* ``UNASSIGNED``
+
+where ``UNASSIGNED`` refers to message type code 0.
+
+Examples::
+
+ mqtt.type:CONNECT;
+ mqtt.type:PUBLISH;
+
+
+mqtt.flags
+----------
+
+Match on a combination of MQTT header flags, separated by commas (``,``). Flags may be prefixed by ``!`` to indicate negation, i.e. a flag prefixed by ``!`` must `not` be set to match.
+
+Valid flags are:
+
+* ``dup`` (duplicate message)
+* ``retain`` (message should be retained on the broker)
+
+Examples::
+
+ mqtt.flags:dup,!retain;
+ mqtt.flags:retain;
+
+
+mqtt.qos
+--------
+
+Match on the Quality of Service request code in the MQTT fixed header.
+Valid values are:
+
+* ``0`` (fire and forget)
+* ``1`` (at least one delivery)
+* ``2`` (exactly one delivery)
+
+Examples::
+
+ mqtt.qos:0;
+ mqtt.qos:2;
+
+
+mqtt.reason_code
+----------------
+
+Match on the numeric value of the reason code that is used in MQTT 5.0 for some message types. Please refer to the specification for the meaning of these values, which are often specific to the message type in question.
+
+Examples::
+
+ # match on attempts to unsubscribe from a non-subscribed topic
+ mqtt.type:UNSUBACK; mqtt.reason_code:17;
+
+ # match on publications that were accepted but there were no subscribers
+ mqtt.type:PUBACK; mqtt.reason_code:16;
+
+ # match on connection attempts by banned clients
+ mqtt.CONNACK; mqtt.reason_code:138;
+
+ # match on failed connection attempts due to bad credentials
+ mqtt.CONNACK; mqtt.reason_code:134;
+
+ # match on connections terminated by server shutdowns
+ mqtt.DISCONNECT; mqtt.reason_code:139;
+
+This keyword is also available under the alias ``mqtt.connack.return_code`` for completeness.
+
+
+mqtt.connack.session_present
+----------------------------
+
+Match on the MQTT CONNACK ``session_present`` flag. Values can be ``yes``, ``true``, ``no`` or ``false``.
+
+Examples::
+
+ mqtt.CONNACK; mqtt.connack.session_present:true;
+
+
+mqtt.connect.clientid
+---------------------
+
+Match on the self-assigned client ID in the MQTT CONNECT message.
+
+Examples::
+
+ mqtt.connect.clientid; pcre:"/^mosq.*/";
+ mqtt.connect.clientid; content:"myclient";
+
+``mqtt.connect.clientid`` is a 'sticky buffer' and can be used as ``fast_pattern``.
+
+
+mqtt.connect.flags
+------------------
+
+Match on a combination of MQTT CONNECT flags, separated by commas (``,``). Flags may be prefixed by ``!`` to indicate negation, i.e. a flag prefixed by ``!`` must `not` be set to match.
+
+Valid flags are:
+
+* ``username`` (message contains a username)
+* ``password`` (message contains a password)
+* ``will`` (message contains a will definition)
+* ``will_retain`` (will should be retained on broker)
+* ``clean_session`` (start with a clean session)
+
+Examples::
+
+ mqtt.connect.flags:username,password,!will;
+ mqtt.connect.flags:username,!password;
+ mqtt.connect.flags:clean_session;
+
+
+mqtt.connect.password
+---------------------
+
+Match on the password credential in the MQTT CONNECT message.
+
+Examples::
+
+ mqtt.connect.password; pcre:"/^123[0-9]*/";
+ mqtt.connect.password; content:"swordfish";
+
+``mqtt.connect.password`` is a 'sticky buffer' and can be used as ``fast_pattern``.
+
+
+mqtt.connect.username
+---------------------
+
+Match on the username credential in the MQTT CONNECT message.
+
+Examples::
+
+ mqtt.connect.username; content:"benson";
+
+``mqtt.connect.username`` is a 'sticky buffer' and can be used as ``fast_pattern``.
+
+
+mqtt.connect.willmessage
+------------------------
+
+Match on the will message in the MQTT CONNECT message, if a will is defined.
+
+Examples::
+
+ mqtt.connect.willmessage; pcre:"/^fooba[rz]/";
+ mqtt.connect.willmessage; content:"hunter2";
+
+``mqtt.connect.willmessage`` is a 'sticky buffer' and can be used as ``fast_pattern``.
+
+
+mqtt.connect.willtopic
+----------------------
+
+Match on the will topic in the MQTT CONNECT message, if a will is defined.
+
+Examples::
+
+ mqtt.connect.willtopic; pcre:"/^hunter[0-9]/";
+
+``mqtt.connect.willtopic`` is a 'sticky buffer' and can be used as ``fast_pattern``.
+
+
+mqtt.publish.message
+--------------------
+
+Match on the payload to be published in the MQTT PUBLISH message.
+
+Examples::
+
+ mqtt.type:PUBLISH; mqtt.publish.message; pcre:"/uid=[0-9]+/";
+ # match on published JPEG images
+ mqtt.type:PUBLISH; mqtt.publish.message; content:"|FF D8 FF E0|"; startswith;
+
+``mqtt.publish.message`` is a 'sticky buffer' and can be used as ``fast_pattern``.
+
+
+mqtt.publish.topic
+------------------
+
+Match on the topic to be published to in the MQTT PUBLISH message.
+
+Examples::
+
+ mqtt.publish.topic; content:"mytopic";
+
+``mqtt.publish.topic`` is a 'sticky buffer' and can be used as ``fast_pattern``.
+
+
+mqtt.subscribe.topic
+--------------------
+
+Match on any of the topics subscribed to in a MQTT SUBSCRIBE message.
+
+Examples::
+
+ mqtt.subscribe.topic; content:"mytopic";
+
+``mqtt.subscribe.topic`` is a 'sticky buffer' and can be used as ``fast_pattern``.
+
+``mqtt.subscribe.topic`` supports multiple buffer matching, see :doc:`multi-buffer-matching`.
+
+
+mqtt.unsubscribe.topic
+----------------------
+
+Match on any of the topics unsubscribed from in a MQTT UNSUBSCRIBE message.
+
+Examples::
+
+ mqtt.unsubscribe.topic; content:"mytopic";
+
+``mqtt.unsubscribe.topic`` is a 'sticky buffer' and can be used as ``fast_pattern``.
+
+``mqtt.unsubscribe.topic`` supports multiple buffer matching, see :doc:`multi-buffer-matching`.
+
+
+Additional information
+----------------------
+
+More information on the protocol can be found here:
+
+* MQTT 3.1: `<https://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html>`_
+* MQTT 3.1.1: `<https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.html>`_
+* MQTT 5.0: `<https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html>`_
diff --git a/doc/userguide/rules/multi-buffer-matching.rst b/doc/userguide/rules/multi-buffer-matching.rst
new file mode 100644
index 0000000..f599659
--- /dev/null
+++ b/doc/userguide/rules/multi-buffer-matching.rst
@@ -0,0 +1,92 @@
+Multiple Buffer Matching
+========================
+
+Suricata 7 and newer now supports matching contents in multiple
+buffers within the same transaction.
+
+For example a single DNS transaction that has two queries in it:
+
+query 1: example.net
+query 2: something.com
+
+Example rule:
+
+.. container:: example-rule
+
+ `alert dns $HOME_NET any -> $EXTERNAL_NET any (msg:"DNS Multiple Question Example Rule"; dns.query; content:"example"; dns.query; content:".com"; classtype:misc-activity; sid:1; rev:1;)`
+
+Within the single DNS query transaction, there are two queries
+and Suricata will set up two instances of a dns.query buffer.
+
+The first ``dns.query`` buffer will look for content:"example";
+
+The second ``dns.query`` buffer will look for content:".com";
+
+The example rule will alert on the example query since all the
+content matches are satisfied for the rule.
+
+For matching multiple headers in HTTP2 traffic a rule using the
+new functionality would look like:
+
+.. container:: example-rule
+
+ `alert http2 any any -> any any (msg:"HTTP2 Multiple Header Buffer Example"; flow:established,to_server; http.request_header; content:"method|3a 20|GET"; http.request_header; content:"authority|3a 20|example.com"; classtype:misc-activity; sid:1; rev:1;)`
+
+With HTTP2 there are multiple headers seen in the same flow record.
+We now have a way to write a rule in a more efficient way using the
+multiple buffer capability.
+
+
+**Note** Existing behavior when using sticky buffers still applies:
+
+Example rule:
+
+.. container:: example-rule
+
+ `alert dns $HOME_NET any -> $EXTERNAL_NET any (msg:"DNS Query Sticky Buffer Classic Example Rule"; dns.query; content:"example"; content:".net"; classtype:misc-activity; sid:1; rev:1;)`
+
+The above rule will alert on a single dns query containing
+"example.net" or "example.domain.net" since the rule content
+matches are within a single ``dns.query`` buffer and all
+content match requirements of the rule are met.
+
+
+**Note:** This is new behavior. In versions of Suricata prior to
+version 7 multiple statements of the same sticky buffer did not
+make a second instance of the buffer. For example:
+
+dns.query; content:"example"; dns.query; content:".com";
+
+would be equivalent to:
+
+dns.query; content:"example"; content:".com";
+
+Using our example from above, the first query is for example.net
+which matches content:"example"; but does not match content:".com";
+
+The second query is for something.com which would match on the
+content:".com"; but not the content:"example";
+
+So with the Suricata behavior prior to Suricata 7, the signature
+would not fire in this case since both content conditions will
+not be met.
+
+Multiple buffer matching is currently enabled for use with the
+following keywords:
+
+* ``dns.query``
+* ``file.data``
+* ``file.magic``
+* ``file.name``
+* ``http.request_header``
+* ``http.response_header``
+* ``http2.header_name``
+* ``ike.vendor``
+* ``krb5_cname``
+* ``krb5_sname``
+* ``mqtt.subscribe.topic``
+* ``mqtt.unsubscribe.topic``
+* ``quic.cyu.hash``
+* ``quic.cyu.string``
+* ``tls.certs``
+* ``tls.cert_subject``
diff --git a/doc/userguide/rules/normalized-buffers/normalization1.png b/doc/userguide/rules/normalized-buffers/normalization1.png
new file mode 100644
index 0000000..a99820c
--- /dev/null
+++ b/doc/userguide/rules/normalized-buffers/normalization1.png
Binary files differ
diff --git a/doc/userguide/rules/payload-keywords.rst b/doc/userguide/rules/payload-keywords.rst
new file mode 100644
index 0000000..9a609a2
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords.rst
@@ -0,0 +1,844 @@
+Payload Keywords
+================
+.. role:: example-rule-emphasis
+
+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.
+
+.. container:: example-rule
+
+ drop tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"ET TROJAN Likely Bot Nick in IRC (USA +..)"; flow:established,to_server; flowbits:isset,is_proto_irc; :example-rule-emphasis:`content:"NICK ";` pcre:"/NICK .*USA.*[0-9]{3,}/i"; reference:url,doc.emergingthreats.net/2008124; classtype:trojan-activity; sid:2008124; rev:2;)
+
+
+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 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 after 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
+
+startswith
+----------
+
+The ``startswith`` keyword is similar to ``depth``. It takes no arguments
+and must follow a ``content`` keyword. It modifies the ``content`` to match
+exactly at the start of a buffer.
+
+Example::
+
+ content:"GET|20|"; startswith;
+
+``startswith`` is a short hand notation for::
+
+ content:"GET|20|"; depth:4; offset:0;
+
+``startswith`` cannot be mixed with ``depth``, ``offset``, ``within`` or
+``distance`` for the same pattern.
+
+endswith
+--------
+
+The ``endswith`` keyword is similar to ``isdataat:!1,relative;``. It takes no
+arguments and must follow a ``content`` keyword. It modifies the ``content`` to
+match exactly at the end of a buffer.
+
+Example::
+
+ content:".php"; endswith;
+
+``endswith`` is a short hand notation for::
+
+ content:".php"; isdataat:!1,relative;
+
+``endswith`` cannot be mixed with ``offset``, ``within`` or
+``distance`` for the same pattern.
+
+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'.
+
+The absolute value for distance must be less than or equal to 1MB (1048576).
+
+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)
+
+The absolute value for within must be less than or equal to 1MB (1048576).
+
+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
+
+rawbytes
+--------
+
+The rawbytes keyword has no effect but is included to be compatible with
+signatures that use it, for example signatures used with Snort.
+
+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
+
+bsize
+-----
+
+With the ``bsize`` keyword, you can match on the length of the buffer. This adds
+precision to the content match, previously this could have been done with ``isdataat``.
+
+An optional operator can be specified; if no operator is present, the operator will
+default to '='. When a relational operator is used, e.g., '<', '>' or '<>' (range),
+the bsize value will be compared using the relational operator. Ranges are inclusive.
+
+If one or more ``content`` keywords precedes ``bsize``, each occurrence of ``content``
+will be inspected and an error will be raised if the content length and the bsize
+value prevent a match.
+
+Format::
+
+ bsize:<number>;
+ bsize:=<number>;
+ bsize:<<number>;
+ bsize:><number>;
+ bsize:<lo-number><><hi-number>;
+
+Examples of ``bsize`` in a rule:
+
+.. container:: example-rule
+
+ alert dns any any -> any any (msg:"bsize exact buffer size"; dns.query; content:"google.com"; bsize:10; sid:1; rev:1;)
+
+ alert dns any any -> any any (msg:"bsize less than value"; dns.query; content:"google.com"; bsize:<25; sid:2; rev:1;)
+
+ alert dns any any -> any any (msg:"bsize buffer less than or equal value"; dns.query; content:"google.com"; bsize:<=20; sid:3; rev:1;)
+
+ alert dns any any -> any any (msg:"bsize buffer greater than value"; dns.query; content:"google.com"; bsize:>8; sid:4; rev:1;)
+
+ alert dns any any -> any any (msg:"bsize buffer greater than or equal value"; dns.query; content:"google.com"; bsize:>=8; sid:5; rev:1;)
+
+ alert dns any any -> any any (msg:"bsize buffer range value"; dns.query; content:"google.com"; bsize:8<>20; sid:6; rev:1;)
+
+
+.. container:: example-rule
+
+ alert dns any any -> any any (msg:"test bsize rule"; dns.query; content:"short"; bsize:<10; sid:124; rev:1;)
+
+.. container:: example-rule
+
+ alert dns any any -> any any (msg:"test bsize rule"; dns.query; content:"longer string"; bsize:>10; sid:125; rev:1;)
+
+.. container:: example-rule
+
+ alert dns any any -> any any (msg:"test bsize rule"; dns.query; content:"middle"; bsize:6<>15; sid:126; rev:1;)
+
+dsize
+-----
+
+With the dsize keyword, you can match on the size of the packet
+payload/data. You can use the keyword for example to look for abnormal
+sizes of payloads which are equal to some n i.e. 'dsize:n'
+not equal 'dsize:!n' less than 'dsize:<n' or greater than 'dsize:>n'
+This may be convenient in detecting buffer overflows.
+
+dsize cannot be used when using app/streamlayer protocol keywords (i.e. http.uri)
+
+Format::
+
+ dsize:[<>!]number; || dsize:min<>max;
+
+Examples of dsize values:
+
+.. container:: example-rule
+
+ alert tcp any any -> any any (msg:"dsize exact size"; dsize:10; sid:1; rev:1;)
+
+ alert tcp any any -> any any (msg:"dsize less than value"; dsize:<10; sid:2; rev:1;)
+
+ alert tcp any any -> any any (msg:"dsize less than or equal value"; dsize:<=10; sid:3; rev:1;)
+
+ alert tcp any any -> any any (msg:"dsize greater than value"; dsize:>8; sid:4; rev:1;)
+
+ alert tcp any any -> any any (msg:"dsize greater than or equal value"; dsize:>=10; sid:5; rev:1;)
+
+ alert tcp any any -> any any (msg:"dsize range value"; dsize:8<>20; sid:6; rev:1;)
+
+ alert tcp any any -> any any (msg:"dsize not equal value"; dsize:!9; sid:7; rev:1;)
+
+byte_test
+---------
+
+The ``byte_test`` keyword extracts ``<num of bytes>`` and performs an operation selected
+with ``<operator>`` against the value in ``<test value>`` at a particular ``<offset>``.
+The ``<bitmask value>`` is applied to the extracted bytes (before the operator is applied),
+and the final result will be right shifted one bit for each trailing ``0`` in
+the ``<bitmask value>``.
+
+Format::
+
+ byte_test:<num of bytes> | <variable_name>, [!]<operator>, <test value>, <offset> [,relative] \
+ [,<endian>][, string, <num type>][, dce][, bitmask <bitmask value>];
+
+
++----------------+------------------------------------------------------------------------------+
+| <num of bytes> | The number of bytes selected from the packet to be converted |
+| | or the name of a byte_extract/byte_math variable. |
++----------------+------------------------------------------------------------------------------+
+| <operator> | |
+| | - [!] Negation can prefix other operators |
+| | - < less than |
+| | - > greater than |
+| | - = equal |
+| | - <= less than or equal |
+| | - >= greater than or equal |
+| | - & bitwise AND |
+| | - ^ bitwise OR |
++----------------+------------------------------------------------------------------------------+
+| <value> | Value to test the converted value against [hex or decimal accepted] |
++----------------+------------------------------------------------------------------------------+
+| <offset> | Number of bytes into the payload |
++----------------+------------------------------------------------------------------------------+
+| [relative] | Offset relative to last content match |
++----------------+------------------------------------------------------------------------------+
+| [endian] | Type of number being read: |
+| | - big (Most significant byte at lowest address) |
+| | - little (Most significant byte at the highest address) |
++----------------+------------------------------------------------------------------------------+
+| [string] <num> | |
+| | - hex - Converted string represented in hex |
+| | - dec - Converted string represented in decimal |
+| | - oct - Converted string represented in octal |
++----------------+------------------------------------------------------------------------------+
+| [dce] | Allow the DCE module to determine the byte order |
++----------------+------------------------------------------------------------------------------+
+| [bitmask] | Applies the AND operator on the bytes converted |
++----------------+------------------------------------------------------------------------------+
+
+
+Example::
+
+ alert tcp any any -> any any \
+ (msg:"Byte_Test Example - Num = Value"; \
+ content:"|00 01 00 02|"; byte_test:2,=,0x01,0;)
+
+ alert tcp any any -> any any \
+ (msg:"Byte_Test Example - Num = Value relative to content"; \
+ content:"|00 01 00 02|"; byte_test:2,=,0x03,2,relative;)
+
+ alert tcp any any -> any any \
+ (msg:"Byte_Test Example - Num != Value"; content:"|00 01 00 02|"; \
+ byte_test:2,!=,0x06,0;)
+
+ alert tcp any any -> any any \
+ (msg:"Byte_Test Example - Detect Large Values"; content:"|00 01 00 02|"; \
+ byte_test:2,>,1000,1,relative;)
+
+ alert tcp any any -> any any \
+ (msg:"Byte_Test Example - Lowest bit is set"; \
+ content:"|00 01 00 02|"; byte_test:2,&,0x01,12,relative;)
+
+ alert tcp any any -> any any (msg:"Byte_Test Example - Compare to String"; \
+ content:"foobar"; byte_test:4,=,1337,1,relative,string,dec;)
+
+
+byte_math
+---------
+
+The ``byte_math`` keyword adds the capability to perform mathematical operations on extracted values with
+an existing variable or a specified value.
+
+When ``relative`` is included, there must be a previous ``content`` or ``pcre`` match.
+
+Note: if ``oper`` is ``/`` and the divisor is 0, there will never be a match on the ``byte_math`` keyword.
+
+The result can be stored in a result variable and referenced by
+other rule options later in the rule.
+
+
+============== ==================================
+ Keyword Modifier
+============== ==================================
+ content offset,depth,distance,within
+ byte_test offset,value
+ byte_jump offset
+ isdataat offset
+============== ==================================
+
+Format::
+
+ byte_math:bytes <num of bytes> | <variable-name> , offset <offset>, oper <operator>, rvalue <rvalue>, \
+ result <result_var> [, relative] [, endian <endian>] [, string <number-type>] \
+ [, dce] [, bitmask <value>];
+
+
++-----------------------+-----------------------------------------------------------------------+
+| <num of bytes> | The number of bytes selected from the packet |
+| | or the name of a byte_extract variable. |
++-----------------------+-----------------------------------------------------------------------+
+| <offset> | Number of bytes into the payload |
++-----------------------+-----------------------------------------------------------------------+
+| oper <operator> | Mathematical operation to perform: +, -, \*, /, <<, >> |
++-----------------------+-----------------------------------------------------------------------+
+| rvalue <rvalue> | Value to perform the math operation with |
++-----------------------+-----------------------------------------------------------------------+
+| result <result-var> | Where to store the computed value |
++-----------------------+-----------------------------------------------------------------------+
+| [relative] | Offset relative to last content match |
++-----------------------+-----------------------------------------------------------------------+
+| [endian <type>] | - big (Most significant byte at lowest address) |
+| | - little (Most significant byte at the highest address) |
+| | - dce (Allow the DCE module to determine the byte order) |
++-----------------------+-----------------------------------------------------------------------+
+| [string <num_type>] | |
+| | - hex Converted data is represented in hex |
+| | - dec Converted data is represented in decimal |
+| | - oct Converted data is represented as octal |
++-----------------------+-----------------------------------------------------------------------+
+| [dce] | Allow the DCE module to determine the byte order |
++-----------------------+-----------------------------------------------------------------------+
+| [bitmask] <value> | The AND operator will be applied to the extracted value |
+| | The result will be right shifted by the number of bits equal to the |
+| | number of trailing zeros in the mask |
++-----------------------+-----------------------------------------------------------------------+
+
+
+Example::
+
+ alert tcp any any -> any any \
+ (msg:"Testing bytemath_body"; \
+ content:"|00 04 93 F3|"; \
+ content:"|00 00 00 07|"; distance:4; within:4; \
+ byte_math:bytes 4, offset 0, oper +, rvalue \
+ 248, result var, relative;)
+
+ alert udp any any -> any any \
+ (byte_extract: 1, 0, extracted_val, relative; \
+ byte_math: bytes 1, offset 1, oper +, rvalue extracted_val, result var; \
+ byte_test: 2, =, var, 13; \
+ msg:"Byte extract and byte math with byte test verification";)
+
+
+byte_jump
+---------
+
+The ``byte_jump`` keyword allows for the ability to select a ``<num of bytes>`` from an ``<offset>`` and moves the detection pointer to that position. Content matches will then be based off the new position.
+
+Format::
+
+ byte_jump:<num of bytes> | <variable-name>, <offset> [, relative][, multiplier <mult_value>] \
+ [, <endian>][, string, <num_type>][, align][, from_beginning][, from_end] \
+ [, post_offset <value>][, dce][, bitmask <value>];
+
+
+
++-----------------------+-----------------------------------------------------------------------+
+| <num of bytes> | The number of bytes selected from the packet to be converted |
+| | or the name of a byte_extract/byte_math variable. |
++-----------------------+-----------------------------------------------------------------------+
+| <offset> | Number of bytes into the payload |
++-----------------------+-----------------------------------------------------------------------+
+| [relative] | Offset relative to last content match |
++-----------------------+-----------------------------------------------------------------------+
+| [multiplier] <value> | Multiple the converted byte by the <value> |
++-----------------------+-----------------------------------------------------------------------+
+| [endian] | - big (Most significant byte at lowest address) |
+| | - little (Most significant byte at the highest address) |
++-----------------------+-----------------------------------------------------------------------+
+| [string] <num_type> | |
+| | - hex Converted data is represented in hex |
+| | - dec Converted data is represented in decimal |
+| | - oct Converted data is represented as octal |
++-----------------------+-----------------------------------------------------------------------+
+| [align] | Rounds the number up to the next 32bit boundary |
++-----------------------+-----------------------------------------------------------------------+
+| [from_beginning] | Jumps forward from the beginning of the packet, instead of |
+| | where the detection pointer is set |
++-----------------------+-----------------------------------------------------------------------+
+| [from_end] | Jump will begin at the end of the payload, instead of |
+| | where the detection point is set |
++-----------------------+-----------------------------------------------------------------------+
+| [post_offset] <value> | After the jump operation has been performed, it will |
+| | jump an additional number of bytes specified by <value> |
++-----------------------+-----------------------------------------------------------------------+
+| [dce] | Allow the DCE module to determine the byte order |
++-----------------------+-----------------------------------------------------------------------+
+| [bitmask] <value> | The AND operator will be applied by <value> and the |
+| | converted bytes, then jump operation is performed |
++-----------------------+-----------------------------------------------------------------------+
+
+
+Example::
+
+ alert tcp any any -> any any \
+ (msg:"Byte_Jump Example"; \
+ content:"Alice"; byte_jump:2,0; content:"Bob";)
+
+ alert tcp any any -> any any \
+ (msg:"Byte_Jump Multiple Jumps"; \
+ byte_jump:2,0; byte_jump:2,0,relative; content:"foobar"; distance:0; within:6;)
+
+ alert tcp any any -> any any \
+ (msg:"Byte_Jump From the End -8 Bytes"; \
+ byte_jump:0,0, from_end, post_offset -8; \
+ content:"|6c 33 33 74|"; distance:0 within:4;)
+
+
+byte_extract
+------------
+
+The ``byte_extract`` keyword extracts ``<num of bytes>`` at a particular ``<offset>`` and stores it in ``<var_name>``. The value in ``<var_name>`` can be used in any modifier that takes a number as an option and in the case of ``byte_test`` it can be used as a value.
+
+Format::
+
+ byte_extract:<num of bytes>, <offset>, <var_name>, [,relative] [,multiplier <mult-value>] \
+ [,<endian>] [, dce] [, string [, <num_type>] [, align <align-value];
+
+
++--------------------+--------------------------------------------------------------------------+
+| <num of bytes> | The number of bytes selected from the packet to be extracted |
++--------------------+--------------------------------------------------------------------------+
+| <offset> | Number of bytes into the payload |
++--------------------+--------------------------------------------------------------------------+
+| <var_name> | The name of the variable in which to store the value |
++--------------------+--------------------------------------------------------------------------+
+| [relative] | Offset relative to last content match |
++--------------------+--------------------------------------------------------------------------+
+| multiplier <value> | multiply the extracted bytes by <mult-value> before storing |
++--------------------+--------------------------------------------------------------------------+
+| [endian] | Type of number being read: |
+| | - big (Most significant byte at lowest address) |
+| | - little (Most significant byte at the highest address) |
++--------------------+--------------------------------------------------------------------------+
+| [string] <num> | |
+| | - hex - Converted string represented in hex |
+| | - dec - Converted string represented in decimal |
+| | - oct - Converted string represented in octal |
++--------------------+--------------------------------------------------------------------------+
+| [dce] | Allow the DCE module to determine the byte order |
++--------------------+--------------------------------------------------------------------------+
+| align <align-value>| Round the extracted value up to the next |
+| | <align-value> byte boundary post-multiplication (if any) |
+| | ; <align-value> may be 2 or 4 |
++--------------------+--------------------------------------------------------------------------+
+
+
+============== ==================================
+ Keyword Modifier
+============== ==================================
+ content offset,depth,distance,within
+ byte_test offset,value
+ byte_math rvalue
+ byte_jump offset
+ isdataat offset
+============== ==================================
+
+Example::
+
+ alert tcp any any -> any any \
+ (msg:"Byte_Extract Example Using distance"; \
+ content:"Alice"; byte_extract:2,0,size; content:"Bob"; distance:size; within:3; sid:1;)
+ alert tcp any any -> any any \
+ (msg:"Byte_Extract Example Using within"; \
+ flow:established,to_server; content:"|00 FF|"; \
+ byte_extract:1,0,len,relative; content:"|5c 00|"; distance:2; within:len; sid:2;)
+ alert tcp any any -> any any \
+ (msg:"Byte_Extract Example Comparing Bytes"; \
+ flow:established,to_server; content:"|00 FF|"; \
+ byte_extract:2,0,cmp_ver,relative; content:"FooBar"; distance:0; byte_test:2,=,cmp_ver,0; sid:3;)
+
+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:<application number>, [<version number>|*], [<procedure number>|*]>;
+
+Example of the rpc keyword in a rule:
+
+.. container:: example-rule
+
+ alert udp $EXTERNAL_NET any -> $HOME_NET 111 (msg:"RPC portmap request yppasswdd"; :example-rule-emphasis:`rpc:100009,*,*;` reference:bugtraq,2763; classtype:rpc-portmap-decode; sid:1296; rev:4;)
+
+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 :ref:`rules-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 (Perl Compatible Regular Expressions)
+------------------------------------------
+.. role:: example-rule-emphasis
+
+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::
+
+ pcre:"/<regex>/opts";
+
+Example of pcre. In this example there will be a match if the payload contains six
+numbers following::
+
+ pcre:"/[0-9]{6}/";
+
+Example of pcre in a signature:
+
+.. container:: example-rule
+
+ drop tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"ET TROJAN Likely Bot Nick in IRC (USA +..)"; flow:established,to_server; flowbits:isset,is_proto_irc; content:"NICK "; :example-rule-emphasis:`pcre:"/NICK .*USA.*[0-9]{3,}/i";` reference:url,doc.emergingthreats.net/2008124; classtype:trojan-activity; sid:2008124; rev:2;)
+
+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: "/<regex>/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 :ref:`HTTP URI Normalization <rules-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 :ref:`HTTP URI Normalization <rules-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.
+
+.. _pcre-update-v1-to-v2:
+
+Changes from PCRE1 to PCRE2
+===========================
+
+The upgrade from PCRE1 to PCRE2 changes the behavior for some
+PCRE expressions.
+
+- ``\I`` is a valid pcre in PCRE1, with a useless escape, so
+ equivalent to ``I``, but it is no longer the case in PCRE2.
+ There are other characters than I exhibiting this pattern
+- ``[\d-a]`` is a valid pcre in PCRE1, with either a digit,
+ a dash or the character ``a``, but the dash must now be escaped
+ with PCRE2 as ``[\d\-a]`` to get the same behavior
+- ``pcre2_substring_copy_bynumber`` now returns an error
+ ``PCRE2_ERROR_UNSET`` instead of ``pcre_copy_substring`` returning
+ no error and giving an empty string. If the behavior of some use
+ case is no longer the expected one, please let us know.
+
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 0000000..c3e9133
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/Legenda_rules.png
Binary files differ
diff --git a/doc/userguide/rules/payload-keywords/content2.png b/doc/userguide/rules/payload-keywords/content2.png
new file mode 100644
index 0000000..cdfe61c
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/content2.png
Binary files differ
diff --git a/doc/userguide/rules/payload-keywords/content3.png b/doc/userguide/rules/payload-keywords/content3.png
new file mode 100644
index 0000000..a92acd6
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/content3.png
Binary files differ
diff --git a/doc/userguide/rules/payload-keywords/content4.png b/doc/userguide/rules/payload-keywords/content4.png
new file mode 100644
index 0000000..943b6fd
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/content4.png
Binary files differ
diff --git a/doc/userguide/rules/payload-keywords/content5.png b/doc/userguide/rules/payload-keywords/content5.png
new file mode 100644
index 0000000..41352ac
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/content5.png
Binary files differ
diff --git a/doc/userguide/rules/payload-keywords/content6.png b/doc/userguide/rules/payload-keywords/content6.png
new file mode 100644
index 0000000..8a4f7bf
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/content6.png
Binary files differ
diff --git a/doc/userguide/rules/payload-keywords/distance.png b/doc/userguide/rules/payload-keywords/distance.png
new file mode 100644
index 0000000..e6154da
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/distance.png
Binary files differ
diff --git a/doc/userguide/rules/payload-keywords/distance1.png b/doc/userguide/rules/payload-keywords/distance1.png
new file mode 100644
index 0000000..096c036
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/distance1.png
Binary files differ
diff --git a/doc/userguide/rules/payload-keywords/distance3.png b/doc/userguide/rules/payload-keywords/distance3.png
new file mode 100644
index 0000000..4ec2b60
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/distance3.png
Binary files differ
diff --git a/doc/userguide/rules/payload-keywords/distance4.png b/doc/userguide/rules/payload-keywords/distance4.png
new file mode 100644
index 0000000..42d2d04
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/distance4.png
Binary files differ
diff --git a/doc/userguide/rules/payload-keywords/distance5.png b/doc/userguide/rules/payload-keywords/distance5.png
new file mode 100644
index 0000000..0481179
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/distance5.png
Binary files differ
diff --git a/doc/userguide/rules/payload-keywords/isdataat1.png b/doc/userguide/rules/payload-keywords/isdataat1.png
new file mode 100644
index 0000000..61606f0
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/isdataat1.png
Binary files differ
diff --git a/doc/userguide/rules/payload-keywords/replace.png b/doc/userguide/rules/payload-keywords/replace.png
new file mode 100644
index 0000000..16e4746
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/replace.png
Binary files differ
diff --git a/doc/userguide/rules/payload-keywords/replace1.png b/doc/userguide/rules/payload-keywords/replace1.png
new file mode 100644
index 0000000..69da275
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/replace1.png
Binary files differ
diff --git a/doc/userguide/rules/payload-keywords/within1.png b/doc/userguide/rules/payload-keywords/within1.png
new file mode 100644
index 0000000..0c816f9
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/within1.png
Binary files differ
diff --git a/doc/userguide/rules/payload-keywords/within2.png b/doc/userguide/rules/payload-keywords/within2.png
new file mode 100644
index 0000000..c60857d
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/within2.png
Binary files 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 0000000..7d74b25
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/within_distance.png
Binary files 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 0000000..e456493
--- /dev/null
+++ b/doc/userguide/rules/payload-keywords/within_distance2.png
Binary files differ
diff --git a/doc/userguide/rules/pcre/pcre3.png b/doc/userguide/rules/pcre/pcre3.png
new file mode 100644
index 0000000..3a55404
--- /dev/null
+++ b/doc/userguide/rules/pcre/pcre3.png
Binary files differ
diff --git a/doc/userguide/rules/pcre/pcre4.png b/doc/userguide/rules/pcre/pcre4.png
new file mode 100644
index 0000000..0b60132
--- /dev/null
+++ b/doc/userguide/rules/pcre/pcre4.png
Binary files differ
diff --git a/doc/userguide/rules/pcre/pcre5.png b/doc/userguide/rules/pcre/pcre5.png
new file mode 100644
index 0000000..7884e91
--- /dev/null
+++ b/doc/userguide/rules/pcre/pcre5.png
Binary files differ
diff --git a/doc/userguide/rules/pcre/pcre6.png b/doc/userguide/rules/pcre/pcre6.png
new file mode 100644
index 0000000..ca73a90
--- /dev/null
+++ b/doc/userguide/rules/pcre/pcre6.png
Binary files differ
diff --git a/doc/userguide/rules/prefilter-keywords.rst b/doc/userguide/rules/prefilter-keywords.rst
new file mode 100644
index 0000000..f1e7710
--- /dev/null
+++ b/doc/userguide/rules/prefilter-keywords.rst
@@ -0,0 +1,81 @@
+=====================
+Prefiltering Keywords
+=====================
+
+.. _rules-keyword-fast_pattern:
+
+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.
+
+
+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/quic-keywords.rst b/doc/userguide/rules/quic-keywords.rst
new file mode 100644
index 0000000..ffeb0be
--- /dev/null
+++ b/doc/userguide/rules/quic-keywords.rst
@@ -0,0 +1,54 @@
+Quic Keywords
+=============
+
+Suricata implements initial support for Quic by parsing the Quic version.
+
+Suricata also derives a CYU hash for earlier versions of Quic.
+
+Quic app-layer parsing must be enabled in the Suricata config file (set 'app-layer.protocols.quic.enabled' to 'yes').
+
+quic.cyu.hash
+---------------
+
+Match on the CYU hash
+
+Examples::
+
+ alert quic any any -> any any (msg:"QUIC CYU HASH"; \
+ quic.cyu.hash; content:"7b3ceb1adc974ad360cfa634e8d0a730"; \
+ sid:1;)
+
+``quic.cyu.hash`` supports multiple buffer matching, see :doc:`multi-buffer-matching`.
+
+quic.cyu.string
+---------------
+
+Match on the CYU string
+
+Examples::
+
+ alert quic any any -> any any (msg:"QUIC CYU STRING"; \
+ quic.cyu.string; content:"46,PAD-SNI-VER-CCS-UAID-TCID-PDMD-SMHL-ICSL-NONP-MIDS-SCLS-CSCT-COPT-IRTT-CFCW-SFCW"; \
+ sid:2;)
+
+``quic.cyu.string`` supports multiple buffer matching, see :doc:`multi-buffer-matching`.
+
+quic.version
+------------
+
+Sticky buffer for matching on the Quic header version in long headers.
+
+Examples::
+
+ alert quic any any -> any any (msg:"QUIC VERSION"; \
+ quic.version; content:"Q046"; \
+ sid:3;)
+
+Additional information
+----------------------
+
+More information on CYU Hash can be found here:
+`<https://engineering.salesforce.com/gquic-protocol-analysis-and-fingerprinting-in-zeek-a4178855d75f>`_
+
+More information on the protocol can be found here:
+`<https://datatracker.ietf.org/doc/html/draft-ietf-quic-transport-17>`_
diff --git a/doc/userguide/rules/rfb-keywords.rst b/doc/userguide/rules/rfb-keywords.rst
new file mode 100644
index 0000000..628b3d8
--- /dev/null
+++ b/doc/userguide/rules/rfb-keywords.rst
@@ -0,0 +1,56 @@
+RFB Keywords
+============
+
+The ``rfb.name`` and ``rfb.sectype`` keywords can be used for matching on various properties of
+RFB (Remote Framebuffer, i.e. VNC) handshakes.
+
+
+rfb.name
+--------
+
+Match on the value of the RFB desktop name field.
+
+Examples::
+
+ rfb.name; content:"Alice's desktop";
+ rfb.name; pcre:"/.* \(screen [0-9]\)$/";
+
+``rfb.name`` is a 'sticky buffer'.
+
+``rfb.name`` can be used as ``fast_pattern``.
+
+
+rfb.secresult
+-------------
+
+Match on the value of the RFB security result, e.g. ``ok``, ``fail``, ``toomany`` or ``unknown``.
+
+Examples::
+
+ rfb.secresult: ok;
+ rfb.secresult: unknown;
+
+
+rfb.sectype
+-----------
+
+Match on the value of the RFB security type field, e.g. ``2`` for VNC challenge-response authentication, ``0`` for no authentication, and ``30`` for Apple's custom Remote Desktop authentication.
+
+This keyword takes a numeric argument after a colon and supports additional qualifiers, such as:
+
+* ``>`` (greater than)
+* ``<`` (less than)
+* ``>=`` (greater than or equal)
+* ``<=`` (less than or equal)
+
+Examples::
+
+ rfb.sectype:2;
+ rfb.sectype:>=3;
+
+
+Additional information
+----------------------
+
+More information on the protocol can be found here:
+`<https://tools.ietf.org/html/rfc6143>`_
diff --git a/doc/userguide/rules/sip-keywords.rst b/doc/userguide/rules/sip-keywords.rst
new file mode 100644
index 0000000..be3662b
--- /dev/null
+++ b/doc/userguide/rules/sip-keywords.rst
@@ -0,0 +1,179 @@
+SIP Keywords
+============
+
+The SIP keywords are implemented as sticky buffers and can be used to match on fields in SIP messages.
+
+============================== ==================
+Keyword Direction
+============================== ==================
+sip.method Request
+sip.uri Request
+sip.request_line Request
+sip.stat_code Response
+sip.stat_msg Response
+sip.response_line Response
+sip.protocol Both
+============================== ==================
+
+sip.method
+----------
+
+This keyword matches on the method found in a SIP request.
+
+Syntax
+~~~~~~
+
+::
+
+ sip.method; content:<method>;
+
+Examples of methods are:
+
+* INVITE
+* BYE
+* REGISTER
+* CANCEL
+* ACK
+* OPTIONS
+
+Examples
+~~~~~~~~
+
+::
+
+ sip.method; content:"INVITE";
+
+sip.uri
+-------
+
+This keyword matches on the uri found in a SIP request.
+
+Syntax
+~~~~~~
+
+::
+
+ sip.uri; content:<uri>;
+
+Where <uri> is an uri that follows the SIP URI scheme.
+
+Examples
+~~~~~~~~
+
+::
+
+ sip.uri; content:"sip:sip.url.org";
+
+sip.request_line
+----------------
+
+This keyword forces the whole SIP request line to be inspected.
+
+Syntax
+~~~~~~
+
+::
+
+ sip.request_line; content:<request_line>;
+
+Where <request_line> is a partial or full line.
+
+Examples
+~~~~~~~~
+
+::
+
+ sip.request_line; content:"REGISTER sip:sip.url.org SIP/2.0"
+
+sip.stat_code
+-------------
+
+This keyword matches on the status code found in a SIP response.
+
+Syntax
+~~~~~~
+
+::
+
+ sip.stat_code; content:<stat_code>
+
+Where <status_code> belongs to one of the following groups of codes:
+
+* 1xx - Provisional Responses
+* 2xx - Successful Responses
+* 3xx - Redirection Responses
+* 4xx - Client Failure Responses
+* 5xx - Server Failure Responses
+* 6xx - Global Failure Responses
+
+Examples
+~~~~~~~~
+
+::
+
+ sip.stat_code; content:"100";
+
+sip.stat_msg
+------------
+
+This keyword matches on the status message found in a SIP response.
+
+Syntax
+~~~~~~
+
+::
+
+ sip.stat_msg; content:<stat_msg>
+
+Where <stat_msg> is a reason phrase associated to a status code.
+
+Examples
+~~~~~~~~
+
+::
+
+ sip.stat_msg; content:"Trying";
+
+sip.response_line
+-----------------
+
+This keyword forces the whole SIP response line to be inspected.
+
+Syntax
+~~~~~~
+
+::
+
+ sip.response_line; content:<response_line>;
+
+Where <response_line> is a partial or full line.
+
+Examples
+~~~~~~~~
+
+::
+
+ sip.response_line; content:"SIP/2.0 100 OK"
+
+sip.protocol
+------------
+
+This keyword matches the protocol field from a SIP request or response line.
+
+If the response line is 'SIP/2.0 100 OK', then this buffer will contain 'SIP/2.0'
+
+Syntax
+~~~~~~
+
+::
+
+ sip.protocol; content:<protocol>
+
+Where <protocol> is the SIP protocol version.
+
+Example
+~~~~~~~
+
+::
+
+ sip.protocol; content:"SIP/2.0"
diff --git a/doc/userguide/rules/smb-keywords.rst b/doc/userguide/rules/smb-keywords.rst
new file mode 100644
index 0000000..02cf190
--- /dev/null
+++ b/doc/userguide/rules/smb-keywords.rst
@@ -0,0 +1,60 @@
+SMB Keywords
+==============
+
+SMB keywords used in both SMB1 and SMB2 protocols.
+
+smb.named_pipe
+--------------
+
+Match on SMB named pipe in tree connect.
+
+Examples::
+
+ smb.named_pipe; content:"IPC"; endswith;
+ smb.named_pipe; content:"strange"; nocase; pcre:"/really$/";
+
+``smb.named_pipe`` is a 'sticky buffer'.
+
+``smb.named_pipe`` can be used as ``fast_pattern``.
+
+smb.share
+---------
+
+Match on SMB share name in tree connect.
+
+Examples::
+
+ smb.share; content:"shared"; endswith;
+ smb.share; content:"strange"; nocase; pcre:"/really$/";
+
+``smb.share`` is a 'sticky buffer'.
+
+``smb.share`` can be used as ``fast_pattern``.
+
+smb.ntlmssp_user
+----------------
+
+Match on SMB ntlmssp user in session setup.
+
+Examples::
+
+ smb.ntlmssp_user; content:"doe"; endswith;
+ smb.ntlmssp_user; content:"doe"; nocase; pcre:"/j(ohn|ane).*doe$/";
+
+``smb.ntlmssp_user`` is a 'sticky buffer'.
+
+``smb.ntlmssp_user`` can be used as ``fast_pattern``.
+
+smb.ntlmssp_domain
+------------------
+
+Match on SMB ntlmssp domain in session setup.
+
+Examples::
+
+ smb.ntlmssp_domain; content:"home"; endswith;
+ smb.ntlmssp_domain; content:"home"; nocase; pcre:"/home(sweet)*$/";
+
+``smb.ntlmssp_domain`` is a 'sticky buffer'.
+
+``smb.ntlmssp_domain`` can be used as ``fast_pattern``.
diff --git a/doc/userguide/rules/snmp-keywords.rst b/doc/userguide/rules/snmp-keywords.rst
new file mode 100644
index 0000000..a5349c2
--- /dev/null
+++ b/doc/userguide/rules/snmp-keywords.rst
@@ -0,0 +1,95 @@
+SNMP keywords
+=============
+
+snmp.version
+------------
+
+SNMP protocol version (integer). Expected values are 1, 2 (for version 2c) or 3.
+
+Syntax::
+
+ snmp.version:[op]<number>
+
+The version can be matched exactly, or compared using the _op_ setting::
+
+ snmp.version:3 # exactly 3
+ snmp.version:<3 # smaller than 3
+ snmp.version:>=2 # greater or equal than 2
+
+Signature example::
+
+ alert snmp any any -> any any (msg:"old SNMP version (<3)"; snmp.version:<3; sid:1; rev:1;)
+
+snmp.community
+--------------
+
+SNMP community strings are like passwords for SNMP messages in version 1 and 2c.
+In version 3, the community string is likely to be encrypted. This keyword will not
+match if the value is not accessible.
+
+The default value for the read-only community string is often "public", and
+"private" for the read-write community string.
+
+Comparison is case-sensitive.
+
+Syntax::
+
+ snmp.community; content:"private";
+
+Signature example::
+
+ alert snmp any any -> any any (msg:"SNMP community private"; snmp.community; content:"private"; sid:2; rev:1;)
+
+``snmp.community`` is a 'sticky buffer'.
+
+``snmp.community`` can be used as ``fast_pattern``.
+
+snmp.usm
+--------
+
+SNMP User-based Security Model (USM) is used in version 3.
+It corresponds to the user name.
+
+Comparison is case-sensitive.
+
+Syntax::
+
+ snmp.usm; content:"admin";
+
+Signature example::
+
+ alert snmp any any -> any any (msg:"SNMP usm admin"; snmp.usm; content:"admin"; sid:2; rev:1;)
+
+``snmp.usm`` is a 'sticky buffer'.
+
+``snmp.usm`` can be used as ``fast_pattern``.
+
+snmp.pdu_type
+-------------
+
+SNMP PDU type (integer).
+
+Common values are:
+
+ - 0: GetRequest
+ - 1: GetNextRequest
+ - 2: Response
+ - 3: SetRequest
+ - 4: TrapV1 (obsolete, was the old Trap-PDU in SNMPv1)
+ - 5: GetBulkRequest
+ - 6: InformRequest
+ - 7: TrapV2
+ - 8: Report
+
+This keyword will not match if the value is not accessible within (for ex, an encrypted
+SNMP v3 message).
+
+
+Syntax::
+
+ snmp.pdu_type:<number>
+
+Signature example::
+
+ alert snmp any any -> any any (msg:"SNMP response"; snmp.pdu_type:2; sid:3; rev:1;)
+
diff --git a/doc/userguide/rules/ssh-keywords.rst b/doc/userguide/rules/ssh-keywords.rst
new file mode 100644
index 0000000..83d2f2f
--- /dev/null
+++ b/doc/userguide/rules/ssh-keywords.rst
@@ -0,0 +1,149 @@
+.. role:: example-rule-emphasis
+
+SSH Keywords
+============
+Suricata has several rule keywords to match on different elements of SSH
+connections.
+
+
+ssh.proto
+---------
+Match on the version of the SSH protocol used. ``ssh.proto`` is a sticky buffer,
+and can be used as a fast pattern. ``ssh.proto`` replaces the previous buffer
+name: ``ssh_proto``. You may continue to use the previous name, but it's
+recommended that existing rules be converted to use the new name.
+
+Format::
+
+ ssh.proto;
+
+Example:
+
+.. container:: example-rule
+
+ alert ssh any any -> any any (msg:"match SSH protocol version"; :example-rule-emphasis:`ssh.proto;` content:"2.0"; sid:1000010;)
+
+The example above matches on SSH connections with SSH version 2.0.
+
+
+ssh.software
+------------
+Match on the software string from the SSH banner. ``ssh.software`` is a sticky
+buffer, and can be used as fast pattern.
+
+``ssh.software`` replaces the previous keyword names: ``ssh_software`` &
+``ssh.softwareversion``. You may continue to use the previous name, but it's
+recommended that rules be converted to use the new name.
+
+Format::
+
+ ssh.software;
+
+Example:
+
+.. container:: example-rule
+
+ alert ssh any any -> any any (msg:"match SSH software string"; :example-rule-emphasis:`ssh.software;` content:"openssh"; nocase; sid:1000020;)
+
+The example above matches on SSH connections where the software string contains
+"openssh".
+
+
+ssh.protoversion
+----------------
+Matches on the version of the SSH protocol used. A value of ``2_compat``
+includes SSH version 1.99.
+
+Format::
+
+ ssh.protoversion:[0-9](\.[0-9])?|2_compat;
+
+Example:
+
+.. container:: example-rule
+
+ alert ssh any any -> any any (msg:"SSH v2 compatible"; :example-rule-emphasis:`ssh.protoversion:2_compat;` sid:1;)
+
+The example above matches on SSH connections with SSH version 2 or 1.99.
+
+.. container:: example-rule
+
+ alert ssh any any -> any any (msg:"SSH v1.10"; :example-rule-emphasis:`ssh.protoversion:1.10;` sid:1;)
+
+The example above matches on SSH connections with SSH version 1.10 only.
+
+
+ssh.softwareversion
+-------------------
+This keyword has been deprecated. Please use ``ssh.software`` instead. Matches
+on the software string from the SSH banner.
+
+Example:
+
+.. container:: example-rule
+
+ alert ssh any any -> any any (msg:"match SSH software string"; :example-rule-emphasis:`ssh.softwareversion:"OpenSSH";` sid:10000040;)
+
+
+Suricata comes with a Hassh integration (https://github.com/salesforce/hassh). Hassh is used to fingerprint ssh clients and servers.
+
+Hassh must be enabled in the Suricata config file (set 'app-layer.protocols.ssh.hassh' to 'yes').
+
+ssh.hassh
+---------
+
+Match on hassh (md5 of of hassh algorithms of client).
+
+Example::
+
+ alert ssh any any -> any any (msg:"match hassh"; \
+ ssh.hassh; content:"ec7378c1a92f5a8dde7e8b7a1ddf33d1";\
+ sid:1000010;)
+
+``ssh.hassh`` is a 'sticky buffer'.
+
+``ssh.hassh`` can be used as ``fast_pattern``.
+
+ssh.hassh.string
+----------------
+
+Match on Hassh string (hassh algorithms of client).
+
+Example::
+
+ alert ssh any any -> any any (msg:"match hassh-string"; \
+ ssh.hassh.string; content:"none,zlib@openssh.com,zlib"; \
+ sid:1000030;)
+
+``ssh.hassh.string`` is a 'sticky buffer'.
+
+``ssh.hassh.string`` can be used as ``fast_pattern``.
+
+ssh.hassh.server
+----------------
+
+Match on hassh (md5 of hassh algorithms of server).
+
+Example::
+
+ alert ssh any any -> any any (msg:"match SSH hash-server"; \
+ ssh.hassh.server; content:"b12d2871a1189eff20364cf5333619ee"; \
+ sid:1000020;)
+
+``ssh.hassh.server`` is a 'sticky buffer'.
+
+``ssh.hassh.server`` can be used as ``fast_pattern``.
+
+ssh.hassh.server.string
+-----------------------
+
+Match on hassh string (hassh algorithms of server).
+
+Example::
+ alert ssh any any -> any any (msg:"match SSH hash-server-string"; \
+ ssh.hassh.server.string; content:"umac-64-etm@openssh.com,umac-128-etm@openssh.com"; \
+ sid:1000040;)
+
+``ssh.hassh.server.string`` is a 'sticky buffer'.
+
+``ssh.hassh.server.string`` can be used as ``fast_pattern``.
diff --git a/doc/userguide/rules/tag.rst b/doc/userguide/rules/tag.rst
new file mode 100644
index 0000000..1b057cb
--- /dev/null
+++ b/doc/userguide/rules/tag.rst
@@ -0,0 +1,133 @@
+Tag
+===
+
+The `tag` keyword allows tagging of the current and future packets.
+
+Tagged packets can be logged in `EVE` and conditional PCAP logging.
+
+Tagging is limited to a scope: `host` or `session` (flow). When using `host` a
+direction can be specified: `src` or `dst`. Tagging will then occur based on the
+`src` or `dst` IP address of the packet generating the alert.
+
+Tagging is further controlled by count: `packets`, `bytes` or `seconds`. If the
+count is ommited built-in defaults will be used:
+
+- for `session`: 256 packets
+- for `host`: 256 packets for the destination IP of the packet triggering the alert
+
+The `tag` keyword can appear multiple times in a rule.
+
+Syntax
+~~~~~~
+
+::
+
+ tag:<scope>[,<count>, <metric>[,<direction>]];
+
+Values for `scope`: `session` and `host`
+Values for `metric`: `packets`, `bytes`, `seconds`
+Values for `direction`: `src` and `dst`
+
+.. note:: "direction" can only be specified if scope is "host" and both "count"
+ and "metric" are also specified.
+
+Examples
+~~~~~~~~
+
+Keyword::
+
+ tag:session; # tags next 256 packets in the flow
+ tag:host; # tags next 256 packets for the dst ip of the alert
+ tag:host,100,packets,src; # tags next 100 packets for src ip of the alert
+ tag:host,3600,seconds,dst; # tags packets for dst host for the next hour
+
+Full rule examples:
+
+.. container:: example-rule
+
+ alert dns any any -> any any (dns.query; content:"evil"; tag:host,60,seconds,src; sid:1;)
+
+.. container:: example-rule
+
+ alert http any any -> any any (http.method; content:"POST"; tag:session; sid:1;)
+
+How to Use Tags
+~~~~~~~~~~~~~~~
+
+EVE
+"""
+
+Tags can be set to generate `EVE` `tag` records:
+
+.. code-block:: yaml
+
+ outputs:
+ - eve-log:
+ enabled: yes
+ filename: eve.json
+ types:
+ - alert:
+ tagged-packets: true
+
+The tagged packets will then be logged with `event_type`: `packet`:
+
+.. code-block:: json
+
+ {
+ "timestamp": "2020-06-03T10:29:17.850417+0000",
+ "flow_id": 1576832511820424,
+ "event_type": "packet",
+ "src_ip": "192.168.0.27",
+ "src_port": 54634,
+ "dest_ip": "192.168.0.103",
+ "dest_port": 22,
+ "proto": "TCP",
+ "pkt_src": "wire/pcap",
+ "packet": "CAAn6mWJAPSNvfrHCABFAAAogkVAAIAG9rfAqAAbwKgAZ9VqABZvnJXH5Zf6aFAQEAljEwAAAAAAAAAA",
+ "packet_info": {
+ "linktype": 1
+ }
+ }
+
+EVE: :ref:`Eve JSON Output <eve-json-output>`
+
+Conditional PCAP Logging
+""""""""""""""""""""""""
+
+Using the conditional PCAP logging option the tag keyword can control which
+packets are logged by the PCAP logging.
+
+.. code-block:: yaml
+
+ outputs:
+ - pcap-log:
+ enabled: yes
+ filename: log.pcap
+ limit: 1000mb
+ max-files: 2000
+ compression: none
+ mode: normal
+ 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 stop being logged.
+ # Use "all" to log all packets or use "alerts" to log only alerted packets and flows or "tag"
+ # to log only flow tagged via the "tag" keyword
+ conditional: tag
+
+PCAP Logging: :ref:`PCAP log <suricata_yaml_pcap_log>`
+
+Tracking by Host/Flow
+~~~~~~~~~~~~~~~~~~~~~
+
+When the tags are using the `session` scope, the tag is added to the
+`Flow` structure. If a packet has no flow, no tagging will happen. No
+errors/warnings are generated for this.
+
+See :ref:`Flow Settings <suricata-yaml-flow-settings>` for managing flow
+limits and resources.
+
+When tags are using the `host` scope, the tag is stored with a `Host`
+object in the host table. The Host table size will affect effectiveness
+of per host tags.
+
+See :ref:`Host Settings <suricata-yaml-host-settings>` for managing host
+table size.
diff --git a/doc/userguide/rules/thresholding.rst b/doc/userguide/rules/thresholding.rst
new file mode 100644
index 0000000..401f573
--- /dev/null
+++ b/doc/userguide/rules/thresholding.rst
@@ -0,0 +1,118 @@
+Thresholding Keywords
+=====================
+
+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 <threshold|limit|both>, track <by_src|by_dst|by_rule|by_both>, count <N>, seconds <T>
+
+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 <by_src|by_dst|by_rule|by_both>, count <N>, seconds <T>
+
+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:!"&amp|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 0000000..dc28c97
--- /dev/null
+++ b/doc/userguide/rules/tls-keywords.rst
@@ -0,0 +1,304 @@
+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_subject`` supports multiple buffer matching, see :doc:`multi-buffer-matching`.
+
+tls.subject
+~~~~~~~~~~~
+
+Legacy keyword to match TLS/SSL certificate Subject field.
+
+example:
+
+::
+
+ tls.subject:"CN=*.googleusercontent.com"
+
+Case sensitive, can't use 'nocase', or other modifiers.
+
+**Note:** ``tls.cert_subject`` replaces the following legacy keywords: ``tls_cert_subject`` and ``tls.subject``.
+It's recommended that rules be converted to use the new one.
+
+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.issuerdn
+~~~~~~~~~~~~
+
+Legacy keyword to match TLS/SSL certificate IssuerDN field
+
+example:
+
+::
+
+ tls.issuerdn:!"CN=Google-Internet-Authority"
+
+Case sensitive, can't use 'nocase', or other modifiers.
+
+**Note:** ``tls.cert_issuer`` replaces the following legacy keywords: ``tls_cert_issuer`` and ``tls.issuerdn``.
+It's recommended that rules be converted to use the new one.
+
+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.cert_serial`` replaces the previous keyword name: ``tls_cert_serial``. You may continue
+to use the previous name, but it's recommended that rules be converted to use
+the new name.
+
+tls.cert_fingerprint
+--------------------
+
+Match on the SHA-1 fingerprint of the certificate.
+
+Example::
+
+ alert tls any any -> any any (msg:"match cert fingerprint"; \
+ tls.cert_fingerprint; \
+ content:"4a:a3:66:76:82:cb:6b:23:bb:c3:58:47:23:a4:63:a7:78:a4:a1:18"; \
+ sid:200023;)
+
+``tls.cert_fingerprint`` is a 'sticky buffer'.
+
+``tls.cert_fingerprint`` can be used as ``fast_pattern``.
+
+``tls.cert_fingerprint`` replaces the previous keyword name: ``tls_cert_fingerprint`` may continue
+to use the previous name, but it's recommended that rules be converted to use
+the new name.
+
+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.sni`` replaces the previous keyword name: ``tls_sni``. You may continue
+to use the previous name, but it's recommended that rules be converted to use
+the new name.
+
+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.certs
+---------
+
+Do a "raw" match on each of the certificates in the TLS certificate chain.
+
+Example::
+
+ alert tls any any -> any any (msg:"match bytes in TLS cert"; tls.certs; \
+ content:"|06 09 2a 86|"; sid:200070;)
+
+``tls.certs`` is a 'sticky buffer'.
+
+``tls.certs`` can be used as ``fast_pattern``.
+
+``tls.certs`` supports multiple buffer matching, see :doc:`multi-buffer-matching`.
+
+tls.version
+-----------
+
+Match on negotiated TLS/SSL version.
+
+Supported values: "1.0", "1.1", "1.2", "1.3"
+
+It is also possible to match versions using a hex string.
+
+Examples::
+
+ tls.version:1.2;
+ tls.version:0x7f12;
+
+The first example matches TLSv1.2, whilst the last example matches TLSv1.3
+draft 16.
+
+ssl_version
+-----------
+
+Match version of SSL/TLS record.
+
+Supported values "sslv2", "sslv3", "tls1.0", "tls1.1", "tls1.2", "tls1.3"
+
+Example::
+
+ alert tls any any -> any any (msg:"match TLSv1.2"; \
+ ssl_version:tls1.2; sid:200030;)
+
+It is also possible to match on several versions at the same time.
+
+Example::
+
+ alert tls any any -> any any (msg:"match SSLv2 and SSLv3"; \
+ ssl_version:sslv2,sslv3; sid:200031;)
+
+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.
+The location can be specified in the `output.tls-store.certs-log-dir` parameter of the yaml configuration file, cf :ref:`suricata-yaml-outputs-tls`..
+
+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.
+
+tls.random
+----------
+
+Matches on the 32 bytes of the TLS random field.
+
+Example::
+
+ alert tls any any -> any any (msg:"TLS random test"; \
+ tls.random; content:"|9b ce 7a 5e 57 5d 77 02 07 c2 9d be 24 01 cc f0 5d cd e1 d2 a5 86 9c 4a 3e ee 38 db 55 1a d9 bc|"; sid: 200074;)
+
+``tls.random`` is a sticky buffer.
+
+tls.random_time
+---------------
+
+Matches on the first 4 bytes of the TLS random field.
+
+Example::
+
+ alert tls any any -> any any (msg:"TLS random_time test"; \
+ tls.random_time; content:"|9b ce 7a 5e|"; sid: 200075;)
+
+``tls.random_time`` is a sticky buffer.
+
+tls.random_bytes
+----------------
+
+Matches on the last 28 bytes of the TLS random field.
+
+Example::
+
+ alert tls any any -> any any (msg:"TLS random_bytes test"; \
+ tls.random_bytes; content:"|57 5d 77 02 07 c2 9d be 24 01 cc f0 5d cd e1 d2 a5 86 9c 4a 3e ee 38 db 55 1a d9 bc|"; sid: 200076;)
+
+``tls.random_bytes`` is a sticky buffer.
+
+tls.cert_chain_len
+------------------
+
+Matches on the TLS certificate chain length.
+
+tls.cert_chain_len supports `<, >, <>, !` and using an exact value.
+
+Example::
+
+ alert tls any any -> any any (msg:"cert chain exact value"; \
+ tls.cert_chain_len:1; classtype:misc-activity; sid:1; rev:1;)
+
+ alert tls any any -> any any (msg:"cert chain less than value"; \
+ tls.cert_chain_len:<2; classtype:misc-activity; sid:2; rev:1;)
+
+ alert tls any any -> any any (msg:"cert chain greater than value"; \
+ tls.cert_chain_len:>0; classtype:misc-activity; sid:2; rev:1;)
+
+ alert tls any any -> any any (msg:"cert chain greater than less than value";\
+ tls.cert_chain_len:0<>2; classtype:misc-activity; sid:3; rev:1;)
+
+ alert tls any any -> any any (msg:"cert chain not value"; \
+ tls.cert_chain_len:!2; classtype:misc-activity; sid:4; rev:1;)
diff --git a/doc/userguide/rules/transforms.rst b/doc/userguide/rules/transforms.rst
new file mode 100644
index 0000000..f730f0d
--- /dev/null
+++ b/doc/userguide/rules/transforms.rst
@@ -0,0 +1,190 @@
+Transformations
+===============
+
+Transformation keywords turn the data at a sticky buffer into something else. Some transformations
+support options for greater control over the transformation process
+
+Example::
+
+ alert http any any -> any any (file_data; strip_whitespace; \
+ content:"window.navigate("; sid:1;)
+
+This example will match on traffic even if there are one or more spaces between
+the ``navigate`` and ``(``.
+
+The transforms can be chained. They are processed in the order in which they
+appear in a rule. Each transform's output acts as input for the next one.
+
+Example::
+
+ alert http any any -> any any (http_request_line; compress_whitespace; to_sha256; \
+ content:"|54A9 7A8A B09C 1B81 3725 2214 51D3 F997 F015 9DD7 049E E5AD CED3 945A FC79 7401|"; sid:1;)
+
+.. note:: not all sticky buffers support transformations yet
+
+dotprefix
+---------
+
+Takes the buffer, and prepends a ``.`` character to help facilitate concise domain checks. For example,
+an input string of ``hello.google.com`` would be modified and become ``.hello.google.com``. Additionally,
+adding the dot allows ``google.com`` to match against ``content:".google.com"``
+
+Example::
+
+ alert dns any any -> any any (dns.query; dotprefix; \
+ content:".microsoft.com"; sid:1;)
+
+This example will match on ``windows.update.microsoft.com`` and
+``maps.microsoft.com.au`` but not ``windows.update.fakemicrosoft.com``.
+
+This rule can be used to match on the domain only; example::
+
+ alert dns any any -> any any (dns.query; dotprefix; \
+ content:".microsoft.com"; endswith; sid:1;)
+
+This example will match on ``windows.update.microsoft.com`` but not
+``windows.update.microsoft.com.au``.
+
+Finally, this rule can be used to match on the TLD only; example::
+
+ alert dns any any -> any any (dns.query; dotprefix; \
+ content:".co.uk"; endswith; sid:1;)
+
+This example will match on ``maps.google.co.uk`` but not
+``maps.google.co.nl``.
+
+strip_whitespace
+----------------
+
+Strips all whitespace as considered by the ``isspace()`` call in C.
+
+Example::
+
+ alert http any any -> any any (file_data; strip_whitespace; \
+ content:"window.navigate("; sid:1;)
+
+compress_whitespace
+-------------------
+
+Compresses all consecutive whitespace into a single space.
+
+to_lowercase
+------------
+
+Converts the buffer to lowercase and passes the value on.
+
+This example alerts if ``http.uri`` contains ``this text has been converted to lowercase``
+
+Example::
+
+ alert http any any -> any any (http.uri; to_lowercase; \
+ content:"this text has been converted to lowercase"; sid:1;)
+
+to_md5
+------
+
+Takes the buffer, calculates the MD5 hash and passes the raw hash value
+on.
+
+Example::
+
+ alert http any any -> any any (http_request_line; to_md5; \
+ content:"|54 A9 7A 8A B0 9C 1B 81 37 25 22 14 51 D3 F9 97|"; sid:1;)
+
+to_uppercase
+------------
+
+Converts the buffer to uppercase and passes the value on.
+
+This example alerts if ``http.uri`` contains ``THIS TEXT HAS BEEN CONVERTED TO LOWERCASE``
+
+Example::
+
+ alert http any any -> any any (http.uri; to_uppercase; \
+ content:"THIS TEXT HAS BEEN CONVERTED TO UPPERCASE"; sid:1;)
+
+to_sha1
+---------
+
+Takes the buffer, calculates the SHA-1 hash and passes the raw hash value
+on.
+
+Example::
+
+ alert http any any -> any any (http_request_line; to_sha1; \
+ content:"|54A9 7A8A B09C 1B81 3725 2214 51D3 F997 F015 9DD7|"; sid:1;)
+
+to_sha256
+---------
+
+Takes the buffer, calculates the SHA-256 hash and passes the raw hash value
+on.
+
+Example::
+
+ alert http any any -> any any (http_request_line; to_sha256; \
+ content:"|54A9 7A8A B09C 1B81 3725 2214 51D3 F997 F015 9DD7 049E E5AD CED3 945A FC79 7401|"; sid:1;)
+
+pcrexform
+---------
+
+Takes the buffer, applies the required regular expression, and outputs the *first captured expression*.
+
+.. note:: this transform requires a mandatory option string containing a regular expression.
+
+
+This example alerts if ``http.request_line`` contains ``/dropper.php``
+Example::
+
+ alert http any any -> any any (msg:"HTTP with pcrexform"; http.request_line; \
+ pcrexform:"[a-zA-Z]+\s+(.*)\s+HTTP"; content:"/dropper.php"; sid:1;)
+
+url_decode
+----------
+
+Decodes url-encoded data, ie replacing '+' with space and '%HH' with its value.
+This does not decode unicode '%uZZZZ' encoding
+
+xor
+---
+
+Takes the buffer, applies xor decoding.
+
+.. note:: this transform requires a mandatory option which is the hexadecimal encoded xor key.
+
+
+This example alerts if ``http.uri`` contains ``password=`` xored with 4-bytes key ``0d0ac8ff``
+Example::
+
+ alert http any any -> any any (msg:"HTTP with xor"; http.uri; \
+ xor:"0d0ac8ff"; content:"password="; sid:1;)
+
+header_lowercase
+----------------
+
+This transform is meant for HTTP/1 HTTP/2 header names normalization.
+It lowercases the header names, while keeping untouched the header values.
+
+The implementation uses a state machine :
+- it lowercases until it finds ``:```
+- it does not change until it finds a new line and switch back to first state
+
+This example alerts for both HTTP/1 and HTTP/2 with a authorization header
+Example::
+
+ alert http any any -> any any (msg:"HTTP authorization"; http.header_names; \
+ header_lowercase; content:"authorization:"; sid:1;)
+
+strip_pseudo_headers
+--------------------
+
+This transform is meant for HTTP/1 HTTP/2 header names normalization.
+It strips HTTP2 pseudo-headers (names and values).
+
+The implementation just strips every line beginning by ``:``.
+
+This example alerts for both HTTP/1 and HTTP/2 with only a user agent
+Example::
+
+ alert http any any -> any any (msg:"HTTP ua only"; http.header_names; \
+ bsize:16; content:"|0d 0a|User-Agent|0d 0a 0d 0a|"; nocase; sid:1;)
diff --git a/doc/userguide/rules/xbits.rst b/doc/userguide/rules/xbits.rst
new file mode 100644
index 0000000..6d45d7b
--- /dev/null
+++ b/doc/userguide/rules/xbits.rst
@@ -0,0 +1,108 @@
+Xbits Keyword
+=============
+
+Set, unset, toggle and check for bits stored per host or ip_pair.
+
+Syntax::
+
+ xbits:<set|unset|isset|isnotset|toggle>,<name>,track <ip_src|ip_dst|ip_pair>;
+ xbits:<set|unset|isset|toggle>,<name>,track <ip_src|ip_dst|ip_pair> \
+ [,expire <seconds>];
+ xbits:<set|unset|isset|toggle>,<name>,track <ip_src|ip_dst|ip_pair> \
+ [,expire <seconds>];
+
+Notes
+~~~~~
+
+- No difference between using ``hostbits`` and ``xbits``
+ with ``track ip_<src|dst>``
+
+- If you ``set`` on a client request and use
+ ``track ip_dst``, if you want to match on the server response,
+ you check it (``isset``) with ``track ip_src``.
+
+- To not alert, use ``noalert;``
+
+- the ``toggle`` option will flip the value of the xbits.
+
+- See also:
+
+ - `https://blog.inliniac.net/2014/12/21/crossing-the-streams-in-suricata/ <https://blog.inliniac.net/2014/12/21/crossing-the-streams-in-suricata/>`_
+ - `http://www.cipherdyne.org/blog/2013/07/crossing-the-streams-in-ids-signature-languages.html <http://www.cipherdyne.org/blog/2013/07/crossing-the-streams-in-ids-signature-languages.html>`_
+
+YAML settings
+-------------
+
+Bits that are stored per host are stored in the Host table. This means that
+host table settings affect hostsbits and xbits per host.
+
+Bits that are stored per IP pair are stored in the IPPair table. This means
+that ippair table settings, especially memcap, affect xbits per ip_pair.
+
+Threading
+---------
+
+Due to subtle timing issues between threads the order of sets and checks
+can be slightly unpredictable.
+
+Unix Socket
+-----------
+
+Hostbits can be added, removed and listed through the unix socket.
+
+Add::
+
+ suricatasc -c "add-hostbit <ip> <bit name> <expire in seconds>"
+ suricatasc -c "add-hostbit 1.2.3.4 blacklist 3600"
+
+If a hostbit is added for an existing hostbit, it's expiry timer is updated.
+
+Remove::
+
+ suricatasc -c "remove-hostbit <ip> <bit name>"
+ suricatasc -c "remove-hostbit 1.2.3.4 blacklist"
+
+List::
+
+ suricatasc -c "list-hostbit <ip>"
+ 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;)