diff --git a/doc/userguide/configuration/suricata-yaml.rst b/doc/userguide/configuration/suricata-yaml.rst index 3dfc950ec641..c43533706424 100644 --- a/doc/userguide/configuration/suricata-yaml.rst +++ b/doc/userguide/configuration/suricata-yaml.rst @@ -1736,21 +1736,26 @@ Encrypted traffic There is no decryption of encrypted traffic, so once the handshake is complete continued tracking of the session is of limited use. The ``encryption-handling`` -option controls the behavior after the handshake. +option in ``app-layer.protocols.tls`` and ``app-layer.protocols.ssh`` controls +the behavior after the handshake. -If ``encryption-handling`` is set to ``default`` (or if the option is not set), -Suricata will continue to track the SSL/TLS session. Inspection will be limited, -as raw ``content`` inspection will still be disabled. There is no point in doing -pattern matching on traffic known to be encrypted. Inspection for (encrypted) -Heartbleed and other protocol anomalies still happens. +If ``encryption-handling`` in TLS protocol is set to ``default`` +(or if the option is not set), Suricata will continue to track the SSL/TLS +session. Inspection will be limited, as raw ``content`` inspection will still +be disabled. There is no point in doing pattern matching on traffic known to +be encrypted. Inspection for (encrypted) Heartbleed and other protocol +anomalies still happens. -When ``encryption-handling`` is set to ``bypass``, all processing of this session is -stopped. No further parsing and inspection happens. If ``stream.bypass`` is enabled -this will lead to the flow being bypassed, either inside Suricata or by the -capture method if it supports it and is configured for it. +.. note:: The ``encryption-handling: default`` option is only available for + SSL/TLS and not for SSH protocol. -Finally, if ``encryption-handling`` is set to ``full``, Suricata will process the -flow as normal, without inspection limitations or bypass. +When ``encryption-handling`` is set to ``bypass``, all processing of this +session is stopped. No further parsing and inspection happens. This will also +lead to the flow being bypassed, either inside Suricata or by the capture method +if it supports it and is configured for it. + +Finally, if ``encryption-handling`` is set to ``full``, Suricata will process +the flow as normal, without inspection limitations or bypass. The option has replaced the ``no-reassemble`` option. If ``no-reassemble`` is present, and ``encryption-handling`` is not, ``false`` is interpreted as @@ -2078,12 +2083,12 @@ are typically provided through the command line, are contained in the node parameters. There are two ways to specify arguments: lengthy and short. Dashes are omitted when describing the arguments. This setup node can be used to set up the memory configuration, accessible NICs, and other EAL-related -parameters, among other things. The node `dpdk.eal-params` also supports -multiple arguments of the same type. This can be useful for EAL arguments -such as `--vdev`, `--allow`, or `--block`. Values for these EAL arguments -are specified as a comma-separated list. -An example of such usage can be found in the example above where the `allow` -argument only makes `0000:3b:00.0` and `0000:3b:00.1` accessible to Suricata. +parameters, among other things. The node `dpdk.eal-params` also supports +multiple arguments of the same type. This can be useful for EAL arguments +such as `--vdev`, `--allow`, or `--block`. Values for these EAL arguments +are specified as a comma-separated list. +An example of such usage can be found in the example above where the `allow` +argument only makes `0000:3b:00.0` and `0000:3b:00.1` accessible to Suricata. arguments with list node. such as --vdev, --allow, --block eal options. The definition of lcore affinity as an EAL parameter is a standard practice. However, lcore parameters like `-l`, `-c`, diff --git a/doc/userguide/performance/ignoring-traffic.rst b/doc/userguide/performance/ignoring-traffic.rst index a2c7a8825528..147849195070 100644 --- a/doc/userguide/performance/ignoring-traffic.rst +++ b/doc/userguide/performance/ignoring-traffic.rst @@ -73,10 +73,14 @@ Example:: encrypted traffic ----------------- -The TLS app layer parser has the ability to stop processing encrypted traffic -after the initial handshake. By setting the `app-layer.protocols.tls.encryption-handling` -option to `bypass` the rest of this flow is ignored. If flow bypass is enabled, -the bypass is done in the kernel or in hardware. +The TLS and SSH app layer parsers have the ability to stop processing +encrypted traffic after the initial handshake. By setting the +`app-layer.protocols.tls.encryption-handling` and +`app-layer.protocols.ssh.encryption-handling` options to `bypass` Suricata +bypasses flows once the handshake is completed and encrypted traffic is +detected. The rest of these flow is ignored. +The bypass is done in the kernel or in hardware, similar to how flow bypass +is done. .. _bypass: diff --git a/doc/userguide/upgrade.rst b/doc/userguide/upgrade.rst index 63e2146280ab..fc88ecba90ca 100644 --- a/doc/userguide/upgrade.rst +++ b/doc/userguide/upgrade.rst @@ -79,6 +79,17 @@ Major changes - sip.content_length - Napatech support has been moved to a capture plugin. See :doc:`Napatech plugin `. +- Encrypted traffic bypass has been decoupled from stream.bypass setting. + This means that encrypted traffic can be bypassed while tracking/fully + inspecting other traffic as well. +- Encrypted SSH traffic bypass is now independently controlled through + `app-layer.protocols.ssh.encryption-handling` setting. The setting can either + be `bypass` or `full`, setting `default` as found in the TLS protocol is + NOT supported. To retain the previous behavior of encrypted traffic bypass + combined with stream depth bypass, set + `app-layer.protocols.ssh.encryption-handling` to `bypass` (while also + setting `app-layer.protocols.tls.encryption-handling` to `bypass` and + `stream.bypass` to `true`). Removals ~~~~~~~~ diff --git a/rust/src/ssh/ssh.rs b/rust/src/ssh/ssh.rs index a6a3871a8e60..4b1d1ffe1a0c 100644 --- a/rust/src/ssh/ssh.rs +++ b/rust/src/ssh/ssh.rs @@ -25,11 +25,16 @@ use crate::frames::Frame; static mut ALPROTO_SSH: AppProto = ALPROTO_UNKNOWN; static HASSH_ENABLED: AtomicBool = AtomicBool::new(false); +static BYPASS_ENABLED: AtomicBool = AtomicBool::new(false); fn hassh_is_enabled() -> bool { HASSH_ENABLED.load(Ordering::Relaxed) } +fn enc_bypass_is_enabled() -> bool { + BYPASS_ENABLED.load(Ordering::Relaxed) +} + #[derive(AppLayerFrameType)] pub enum SshFrameType { RecordHdr, @@ -197,11 +202,18 @@ impl SSHState { unsafe { AppLayerParserStateSetFlag( pstate, - APP_LAYER_PARSER_NO_INSPECTION - | APP_LAYER_PARSER_NO_REASSEMBLY - | APP_LAYER_PARSER_BYPASS_READY, + APP_LAYER_PARSER_NO_INSPECTION, ); } + if enc_bypass_is_enabled() { + unsafe { + AppLayerParserStateSetFlag( + pstate, + APP_LAYER_PARSER_NO_REASSEMBLY + | APP_LAYER_PARSER_BYPASS_READY, + ); + } + } } } _ => {} @@ -549,6 +561,16 @@ pub extern "C" fn rs_ssh_hassh_is_enabled() -> bool { hassh_is_enabled() } +#[no_mangle] +pub extern "C" fn rs_ssh_enable_bypass() { + BYPASS_ENABLED.store(true, Ordering::Relaxed) +} + +#[no_mangle] +pub extern "C" fn rs_ssh_enc_bypass_is_enabled() -> bool { + enc_bypass_is_enabled() +} + #[no_mangle] pub unsafe extern "C" fn rs_ssh_tx_get_log_condition( tx: *mut std::os::raw::c_void) -> bool { let tx = cast_pointer!(tx, SSHTransaction); diff --git a/src/app-layer-ssh.c b/src/app-layer-ssh.c index 71bc786ad6b4..979f4b40b038 100644 --- a/src/app-layer-ssh.c +++ b/src/app-layer-ssh.c @@ -55,6 +55,8 @@ /* HASSH fingerprints are disabled by default */ #define SSH_CONFIG_DEFAULT_HASSH false +/* Bypassing the encrypted part of the connections */ +#define SSH_CONFIG_DEFAULT_BYPASS true static int SSHRegisterPatternsForProtocolDetection(void) { @@ -103,6 +105,23 @@ void RegisterSSHParsers(void) if (RunmodeIsUnittests() || enable_hassh) { rs_ssh_enable_hassh(); } + + bool enc_bypass = SSH_CONFIG_DEFAULT_BYPASS; + ConfNode *enc_handle = ConfGetNode("app-layer.protocols.ssh.encryption-handling"); + if (enc_handle != NULL && enc_handle->val != NULL) { + if (strcmp(enc_handle->val, "full") == 0) { + enc_bypass = false; + } else if (strcmp(enc_handle->val, "bypass") == 0) { + enc_bypass = true; + } else { + enc_bypass = SSH_CONFIG_DEFAULT_BYPASS; + } + } + + if (enc_bypass) { + SCLogConfig("ssh: bypass on the start of encryption enabled"); + rs_ssh_enable_bypass(); + } } SCLogDebug("Registering Rust SSH parser."); diff --git a/src/stream-tcp.c b/src/stream-tcp.c index eafedc187c39..4fee1c7cc777 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -5659,17 +5659,13 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, } if (ssn->flags & STREAMTCP_FLAG_BYPASS) { - /* we can call bypass callback, if enabled */ - if (StreamTcpBypassEnabled()) { - PacketBypassCallback(p); - } - - /* if stream is dead and we have no detect engine at all, bypass. */ + PacketBypassCallback(p); } else if (g_detect_disabled && (ssn->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) && (ssn->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) && StreamTcpBypassEnabled()) { + /* if stream is dead and we have no detect engine at all, bypass. */ SCLogDebug("bypass as stream is dead and we have no rules"); PacketBypassCallback(p); } diff --git a/suricata.yaml.in b/suricata.yaml.in index 7dd7cb588675..5f50276f5524 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -943,7 +943,14 @@ app-layer: #enabled: yes ssh: enabled: yes - #hassh: yes + # hassh: no + + # What to do when the encrypted communications start: + # - bypass: stop processing this flow as much as possible. + # Offload flow bypass to kernel or hardware if possible. + # - full: keep tracking and inspection as normal + # + # encryption-handling: full doh2: enabled: yes http2: