From 0b20011a9f31668a70218c965e95959df49362f4 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Sat, 30 May 2026 08:03:44 +0200 Subject: [PATCH] llmnr: implement sticky buffers Add detection keywords for LLMNR protocol inspection: - llmnr.queries.rrname - llmnr.answers.rrname - llmnr.authorities.rrname - llmnr.additionals.rrname - llmnr.response.rrname LLMNR reuses the existing DNS functions since it follows the same protocol structure. The implementation registers LLMNR-specific keywords that leverage the DNS data extraction functions. Both to_server and to_client directions are supported. Ticket #8366 --- src/detect-dns-name.c | 52 +++++++++++++++++++++++++++++++++++++++ src/detect-dns-response.c | 36 +++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/src/detect-dns-name.c b/src/detect-dns-name.c index 8bc3a6493e..a47ec1cb9b 100644 --- a/src/detect-dns-name.c +++ b/src/detect-dns-name.c @@ -51,6 +51,11 @@ static int mdns_answer_buffer_id = 0; static int mdns_authority_buffer_id = 0; static int mdns_additional_buffer_id = 0; +static int llmnr_query_buffer_id = 0; +static int llmnr_answer_buffer_id = 0; +static int llmnr_authority_buffer_id = 0; +static int llmnr_additional_buffer_id = 0; + static int DetectSetupDNS(DetectEngineCtx *de_ctx, Signature *s, const char *str, int id) { if (SCDetectBufferSetActiveList(de_ctx, s, id) < 0) { @@ -75,6 +80,18 @@ static int DetectSetupMDNS(DetectEngineCtx *de_ctx, Signature *s, const char *st return 0; } +static int DetectSetupLLMNR(DetectEngineCtx *de_ctx, Signature *s, const char *str, int id) +{ + if (SCDetectBufferSetActiveList(de_ctx, s, id) < 0) { + return -1; + } + if (SCDetectSignatureSetAppProto(s, ALPROTO_LLMNR) < 0) { + return -1; + } + + return 0; +} + static int SetupQueryBuffer(DetectEngineCtx *de_ctx, Signature *s, const char *str) { return DetectSetupDNS(de_ctx, s, str, query_buffer_id); @@ -115,6 +132,26 @@ static int SetupAuthoritiesBufferMdns(DetectEngineCtx *de_ctx, Signature *s, con return DetectSetupMDNS(de_ctx, s, str, mdns_authority_buffer_id); } +static int SetupQueryBufferLlmnr(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + return DetectSetupLLMNR(de_ctx, s, str, llmnr_query_buffer_id); +} + +static int SetupAnswerBufferLlmnr(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + return DetectSetupLLMNR(de_ctx, s, str, llmnr_answer_buffer_id); +} + +static int SetupAdditionalsBufferLlmnr(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + return DetectSetupLLMNR(de_ctx, s, str, llmnr_additional_buffer_id); +} + +static int SetupAuthoritiesBufferLlmnr(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + return DetectSetupLLMNR(de_ctx, s, str, llmnr_authority_buffer_id); +} + static int Register(const char *keyword, const char *desc, const char *doc, int (*Setup)(DetectEngineCtx *, Signature *, const char *), InspectionMultiBufferGetDataPtr GetBufferFn, AppProto alproto) @@ -166,4 +203,19 @@ void DetectDnsNameRegister(void) Register("mdns.authorities.rrname", "mDNS authorities rrname sticky buffer", "/rules/mdns-keywords.html#mdns-authorities-rrname", SetupAuthoritiesBufferMdns, SCDnsTxGetAuthorityName, ALPROTO_MDNS); + + llmnr_query_buffer_id = Register("llmnr.queries.rrname", "LLMNR query rrname sticky buffer", + "/rules/llmnr-keywords.html#llmnr-queries-rrname", SetupQueryBufferLlmnr, + SCDnsTxGetQueryName, ALPROTO_LLMNR); + llmnr_answer_buffer_id = Register("llmnr.answers.rrname", "LLMNR answer rrname sticky buffer", + "/rules/llmnr-keywords.html#llmnr-answers-rrname", SetupAnswerBufferLlmnr, + SCDnsTxGetAnswerName, ALPROTO_LLMNR); + llmnr_additional_buffer_id = + Register("llmnr.additionals.rrname", "LLMNR additionals rrname sticky buffer", + "/rules/llmnr-keywords.html#llmnr-additionals-rrname", + SetupAdditionalsBufferLlmnr, SCDnsTxGetAdditionalName, ALPROTO_LLMNR); + llmnr_authority_buffer_id = + Register("llmnr.authorities.rrname", "LLMNR authorities rrname sticky buffer", + "/rules/llmnr-keywords.html#llmnr-authorities-rrname", + SetupAuthoritiesBufferLlmnr, SCDnsTxGetAuthorityName, ALPROTO_LLMNR); } diff --git a/src/detect-dns-response.c b/src/detect-dns-response.c index 81ac31304d..98e9734044 100644 --- a/src/detect-dns-response.c +++ b/src/detect-dns-response.c @@ -35,6 +35,7 @@ static int detect_buffer_id = 0; static int mdns_detect_buffer_id = 0; +static int llmnr_detect_buffer_id = 0; typedef struct PrefilterMpm { int list_id; @@ -82,6 +83,18 @@ static int MdnsDetectSetup(DetectEngineCtx *de_ctx, Signature *s, const char *st return 0; } +static int LlmnrDetectSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) +{ + if (SCDetectBufferSetActiveList(de_ctx, s, llmnr_detect_buffer_id) < 0) { + return -1; + } + if (SCDetectSignatureSetAppProto(s, ALPROTO_LLMNR) < 0) { + return -1; + } + + return 0; +} + static InspectionBuffer *GetBuffer(DetectEngineThreadCtx *det_ctx, uint8_t flags, const DetectEngineTransforms *transforms, void *txv, struct DnsResponseGetDataArgs *cbdata, int list_id, bool get_rdata) @@ -349,6 +362,28 @@ static void SCDetectMdnsResponseRrnameRegister(void) mdns_detect_buffer_id = DetectBufferTypeGetByName(keyword); } +static void SCDetectLlmnrResponseRrnameRegister(void) +{ + static const char *keyword = "llmnr.response.rrname"; + int keyword_id = SCDetectHelperNewKeywordId(); + sigmatch_table[keyword_id].name = keyword; + sigmatch_table[keyword_id].desc = "LLMNR response rrname buffer"; + sigmatch_table[keyword_id].url = "/rules/llmnr-keywords.html#llmnr-response-rrname"; + sigmatch_table[keyword_id].Setup = LlmnrDetectSetup; + sigmatch_table[keyword_id].flags |= SIGMATCH_NOOPT; + sigmatch_table[keyword_id].flags |= SIGMATCH_INFO_STICKY_BUFFER; + + DetectAppLayerInspectEngineRegister( + keyword, ALPROTO_LLMNR, SIG_FLAG_TOCLIENT, 1, DetectEngineInspectCb, NULL); + DetectAppLayerMpmRegister(keyword, SIG_FLAG_TOCLIENT, 2, DetectDnsResponsePrefilterMpmRegister, + NULL, ALPROTO_LLMNR, 1); + + DetectBufferTypeSetDescriptionByName(keyword, "llmnr response rdata"); + DetectBufferTypeSupportsMultiInstance(keyword); + + llmnr_detect_buffer_id = DetectBufferTypeGetByName(keyword); +} + void DetectDnsResponseRegister(void) { static const char *keyword = "dns.response.rrname"; @@ -371,4 +406,5 @@ void DetectDnsResponseRegister(void) detect_buffer_id = DetectBufferTypeGetByName(keyword); SCDetectMdnsResponseRrnameRegister(); + SCDetectLlmnrResponseRrnameRegister(); }