use std::ffi::CString;
use std::sync::atomic::{AtomicBool, Ordering};
+#[repr(C)]
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[allow(non_camel_case_types)]
+pub enum SshEncryptionHandling {
+ SSH_HANDLE_ENCRYPTION_TRACK_ONLY = 0, // Disable raw content inspection, continue tracking
+ SSH_HANDLE_ENCRYPTION_BYPASS = 1, // Skip processing of flow, bypass if possible
+ SSH_HANDLE_ENCRYPTION_FULL = 2, // Handle fully like any other protocol
+}
+
static mut ALPROTO_SSH: AppProto = ALPROTO_UNKNOWN;
static HASSH_ENABLED: AtomicBool = AtomicBool::new(false);
+static mut ENCRYPTION_BYPASS_ENABLED: SshEncryptionHandling = SshEncryptionHandling::SSH_HANDLE_ENCRYPTION_TRACK_ONLY;
+
fn hassh_is_enabled() -> bool {
HASSH_ENABLED.load(Ordering::Relaxed)
}
+fn encryption_bypass_mode() -> SshEncryptionHandling {
+ unsafe { ENCRYPTION_BYPASS_ENABLED }
+}
+
#[derive(AppLayerFrameType)]
pub enum SshFrameType {
RecordHdr,
parser::MessageCode::NewKeys => {
hdr.flags = SSHConnectionState::SshStateFinished;
if ohdr.flags >= SSHConnectionState::SshStateFinished {
- unsafe {
- AppLayerParserStateSetFlag(
- pstate,
- APP_LAYER_PARSER_NO_INSPECTION
+ let mut flags = 0;
+
+ match encryption_bypass_mode() {
+ SshEncryptionHandling::SSH_HANDLE_ENCRYPTION_BYPASS => {
+ flags |= APP_LAYER_PARSER_NO_INSPECTION
| APP_LAYER_PARSER_NO_REASSEMBLY
- | APP_LAYER_PARSER_BYPASS_READY,
- );
+ | APP_LAYER_PARSER_BYPASS_READY;
+ }
+ SshEncryptionHandling::SSH_HANDLE_ENCRYPTION_TRACK_ONLY => {
+ flags |= APP_LAYER_PARSER_NO_INSPECTION;
+ }
+ _ => {}
+ }
+
+ if flags != 0 {
+ unsafe {
+ AppLayerParserStateSetFlag(pstate, flags);
+ }
}
}
}
hassh_is_enabled()
}
+#[no_mangle]
+pub extern "C" fn SCSshEnableBypass(mode: SshEncryptionHandling) {
+ unsafe {
+ ENCRYPTION_BYPASS_ENABLED = mode;
+ }
+}
+
#[no_mangle]
pub unsafe extern "C" fn SCSshTxGetLogCondition(tx: *mut std::os::raw::c_void) -> bool {
let tx = cast_pointer!(tx, SSHTransaction);
/* HASSH fingerprints are disabled by default */
#define SSH_CONFIG_DEFAULT_HASSH false
+/* Bypassing the encrypted part of the connections */
+#define SSH_CONFIG_DEFAULT_ENCRYPTION_BYPASS SSH_HANDLE_ENCRYPTION_TRACK_ONLY
static int SSHRegisterPatternsForProtocolDetection(void)
{
if (RunmodeIsUnittests() || enable_hassh) {
SCSshEnableHassh();
}
+
+ SshEncryptionHandling encryption_bypass = SSH_CONFIG_DEFAULT_ENCRYPTION_BYPASS;
+ SCConfNode *encryption_node = SCConfGetNode("app-layer.protocols.ssh.encryption-handling");
+ if (encryption_node != NULL && encryption_node->val != NULL) {
+ if (strcmp(encryption_node->val, "full") == 0) {
+ encryption_bypass = SSH_HANDLE_ENCRYPTION_FULL;
+ } else if (strcmp(encryption_node->val, "track-only") == 0) {
+ encryption_bypass = SSH_HANDLE_ENCRYPTION_TRACK_ONLY;
+ } else if (strcmp(encryption_node->val, "bypass") == 0) {
+ encryption_bypass = SSH_HANDLE_ENCRYPTION_BYPASS;
+ } else {
+ encryption_bypass = SSH_CONFIG_DEFAULT_ENCRYPTION_BYPASS;
+ }
+ }
+
+ if (encryption_bypass) {
+ SCLogConfig("ssh: bypass on the start of encryption enabled");
+ SCSshEnableBypass(encryption_bypass);
+ }
}
SCLogDebug("Registering Rust SSH parser.");
ssh:
enabled: yes
#hassh: yes
+
+ # What to do when the encrypted communications start:
+ # - track-only: keep tracking but stop inspection (default)
+ # - full: keep tracking and inspect as normal
+ # - bypass: stop processing this flow as much as possible.
+ # Offload flow bypass to kernel or hardware if possible.
+ # For the best performance, select 'bypass'.
+ #
+ # encryption-handling: track-only
doh2:
enabled: yes
http2: