static InspectionBuffer *Ja4DetectGetHash(DetectEngineThreadCtx *det_ctx,
const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
const int list_id);
+#ifdef UNITTESTS
+static void DetectJa4RegisterTests(void);
+#endif
static int g_ja4_hash_buffer_id = 0;
#endif
sigmatch_table[DETECT_JA4_HASH].url = "/rules/ja4-keywords.html#ja4-hash";
#ifdef HAVE_JA4
sigmatch_table[DETECT_JA4_HASH].Setup = DetectJa4HashSetup;
+#ifdef UNITTESTS
+ sigmatch_table[DETECT_JA4_HASH].RegisterTests = DetectJa4RegisterTests;
+#endif
#else /* HAVE_JA4 */
sigmatch_table[DETECT_JA4_HASH].Setup = DetectJA4SetupNoSupport;
#endif /* HAVE_JA4 */
if (DetectBufferSetActiveList(de_ctx, s, g_ja4_hash_buffer_id) < 0)
return -1;
- if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) {
+ AppProto alprotos[] = { ALPROTO_TLS, ALPROTO_QUIC, ALPROTO_UNKNOWN };
+ if (DetectSignatureSetMultiAppProto(s, alprotos) < 0) {
SCLogError("rule contains conflicting protocols.");
return -1;
}
}
return -2;
}
- s->init_data->init_flags |= SIG_FLAG_INIT_JA;
return 0;
}
}
return buffer;
}
+
+#ifdef UNITTESTS
+static int DetectJa4TestParse01(void)
+{
+ DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+
+ // invalid tests
+ Signature *s =
+ SigInit(de_ctx, "alert ip any any -> any any (sid: 1; file.data; content: \"toto\"; "
+ "ja4.hash; content: \"q13d0310h3_55b375c5d22e_cd85d2d88918\";)");
+ // cannot have file.data with ja4.hash (quic or tls)
+ FAIL_IF_NOT_NULL(s);
+ s = SigInit(de_ctx, "alert ip any any -> any any (sid: 1; "
+ "ja4.hash; content: \"q13d0310h3_55b375c5d22e_cd85d2d88918\"; file.data; "
+ "content: \"toto\";)");
+ // cannot have file.data with ja4.hash (quic or tls)
+ FAIL_IF_NOT_NULL(s);
+ s = SigInit(de_ctx, "alert smb any any -> any any (sid: 1; "
+ "ja4.hash; content: \"q13d0310h3_55b375c5d22e_cd85d2d88918\";)");
+ // cannot have alproto=smb with ja4.hash (quic or tls)
+ FAIL_IF_NOT_NULL(s);
+ s = SigInit(de_ctx, "alert ip any any -> any any (sid: 1; "
+ "ja4.hash; content: \"q13d0310h3_55b375c5d22e_cd85d2d88918\"; smb.share; "
+ "content:\"toto\";)");
+ // cannot have a smb keyword with ja4.hash (quic or tls)
+ FAIL_IF_NOT_NULL(s);
+ s = SigInit(de_ctx, "alert ip any any -> any any (sid: 1; "
+ "smb.share; content:\"toto\"; ja4.hash; content: "
+ "\"q13d0310h3_55b375c5d22e_cd85d2d88918\";)");
+ // cannot have a smb keyword with ja4.hash (quic or tls)
+ FAIL_IF_NOT_NULL(s);
+
+ // valid tests
+ s = DetectEngineAppendSig(de_ctx,
+ "alert ip any any -> any any (sid: 1; "
+ "ja4.hash; content: \"q13d0310h3_55b375c5d22e_cd85d2d88918\";)");
+ // just ja4.hash any proto
+ FAIL_IF_NULL(s);
+ s = DetectEngineAppendSig(de_ctx,
+ "alert quic any any -> any any (sid: 2; "
+ "ja4.hash; content: \"q13d0310h3_55b375c5d22e_cd85d2d88918\";)");
+ // just ja4.hash only quic
+ FAIL_IF_NULL(s);
+ s = DetectEngineAppendSig(de_ctx,
+ "alert tls any any -> any any (sid: 3; "
+ "ja4.hash; content: \"q13d0310h3_55b375c5d22e_cd85d2d88918\";)");
+ // just ja4.hash only tls
+ FAIL_IF_NULL(s);
+ s = DetectEngineAppendSig(de_ctx,
+ "alert ip any any -> any any (sid: 4; "
+ "ja4.hash; content: \"q13d0310h3_55b375c5d22e_cd85d2d88918\"; "
+ "quic.version; content:\"|00|\";)");
+ // ja4.hash and a quic keyword
+ FAIL_IF_NULL(s);
+ DetectEngineCtxFree(de_ctx);
+ PASS;
+}
+
+static void DetectJa4RegisterTests(void)
+{
+ UtRegisterTest("DetectJa4TestParse01", DetectJa4TestParse01);
+}
#endif
+
+#endif // HAVE_JA4
}
DetectLuaPostSetup(s);
- if ((s->init_data->init_flags & SIG_FLAG_INIT_JA) && s->alproto != ALPROTO_UNKNOWN &&
- s->alproto != ALPROTO_TLS && s->alproto != ALPROTO_QUIC) {
- SCLogError("Cannot have ja3/ja4 with protocol %s.", AppProtoToString(s->alproto));
- SCReturnInt(0);
- }
if ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 ||
(s->init_data->init_flags & SIG_FLAG_INIT_FILEDATA)) {
if (s->alproto != ALPROTO_UNKNOWN &&
"support file matching",
AppProtoToString(s->alproto));
SCReturnInt(0);
+ } else if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
+ bool found = false;
+ for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
+ if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
+ break;
+ }
+ if (AppLayerParserSupportsFiles(IPPROTO_TCP, s->init_data->alprotos[i])) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ SCLogError("No protocol support file matching");
+ SCReturnInt(0);
+ }
}
if (s->alproto == ALPROTO_HTTP2 && (s->file_flags & FILE_SIG_NEED_FILENAME)) {
SCLogError("protocol HTTP2 doesn't support file name matching");