]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
DNS: add /F modifier to pcre to inspect DNS query name
authorVictor Julien <victor@inliniac.net>
Sun, 21 Apr 2013 11:34:55 +0000 (13:34 +0200)
committerVictor Julien <victor@inliniac.net>
Thu, 27 Jun 2013 12:25:58 +0000 (14:25 +0200)
src/detect-dns-query.c
src/detect-pcre.c
src/detect-pcre.h

index 3902d828eaa0553bd989e34c83800a219b60c0f6..38acf1eaa62b8a99afc0383becba07319bb4f068 100644 (file)
@@ -738,6 +738,102 @@ end:
     UTHFreePacket(p4);
     return result;
 }
+
+/** \test simple google.com query matching, pcre */
+static int DetectDnsQueryTest06(void) {
+    /* google.com */
+    uint8_t buf[] = {   0x10, 0x32, 0x01, 0x00, 0x00, 0x01,
+                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                        0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C,
+                        0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00,
+                        0x00, 0x10, 0x00, 0x01, };
+    int result = 0;
+    Flow f;
+    DNSState *dns_state = NULL;
+    Packet *p = NULL;
+    Signature *s = NULL;
+    ThreadVars tv;
+    DetectEngineThreadCtx *det_ctx = NULL;
+
+    memset(&tv, 0, sizeof(ThreadVars));
+    memset(&f, 0, sizeof(Flow));
+
+    p = UTHBuildPacket(buf, sizeof(buf), IPPROTO_UDP);
+
+    FLOW_INITIALIZE(&f);
+    f.flags |= FLOW_IPV4;
+    f.proto = IPPROTO_UDP;
+
+    p->flow = &f;
+    p->flags |= PKT_HAS_FLOW;
+    p->flowflags |= FLOW_PKT_TOSERVER;
+    f.alproto = ALPROTO_DNS_UDP;
+
+    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+    if (de_ctx == NULL) {
+        goto end;
+    }
+    de_ctx->mpm_matcher = MPM_AC;
+    de_ctx->flags |= DE_QUIET;
+
+    s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any "
+                                      "(msg:\"Test dns_query option\"; "
+                                      "content:\"google\"; nocase; dns_query; "
+                                      "pcre:\"/google\\.com$/iF\"; sid:1;)");
+    if (s == NULL) {
+        goto end;
+    }
+    s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any "
+                                      "(msg:\"Test dns_query option\"; "
+                                      "content:\"google\"; nocase; dns_query; "
+                                      "pcre:\"/^\\.[a-z]{2,3}$/iRF\"; sid:2;)");
+    if (s == NULL) {
+        goto end;
+    }
+
+
+    SigGroupBuild(de_ctx);
+    DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
+
+    int r = AppLayerParse(NULL, &f, ALPROTO_DNS_UDP, STREAM_TOSERVER, buf, sizeof(buf));
+    if (r != 0) {
+        printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+        goto end;
+    }
+
+    dns_state = f.alstate;
+    if (dns_state == NULL) {
+        printf("no dns state: ");
+        goto end;
+    }
+
+    /* do detect */
+    SigMatchSignatures(&tv, de_ctx, det_ctx, p);
+
+    if (!(PacketAlertCheck(p, 1))) {
+        printf("sig 1 didn't alert, but it should have: ");
+        goto end;
+    }
+    if (!(PacketAlertCheck(p, 2))) {
+        printf("sig 2 didn't alert, but it should have: ");
+        goto end;
+    }
+
+    result = 1;
+
+end:
+    if (det_ctx != NULL)
+        DetectEngineThreadCtxDeinit(&tv, det_ctx);
+    if (de_ctx != NULL)
+        SigGroupCleanup(de_ctx);
+    if (de_ctx != NULL)
+        DetectEngineCtxFree(de_ctx);
+
+    FLOW_DESTROY(&f);
+    UTHFreePacket(p);
+    return result;
+}
+
 #endif
 
 static void DetectDnsQueryRegisterTests(void) {
@@ -747,5 +843,6 @@ static void DetectDnsQueryRegisterTests(void) {
     UtRegisterTest("DetectDnsQueryTest03 -- tcp", DetectDnsQueryTest03, 1);
     UtRegisterTest("DetectDnsQueryTest04 -- tcp splicing", DetectDnsQueryTest04, 1);
     UtRegisterTest("DetectDnsQueryTest05 -- tcp splicing/multi tx", DetectDnsQueryTest05, 1);
+    UtRegisterTest("DetectDnsQueryTest06 -- pcre", DetectDnsQueryTest06, 1);
 #endif
 }
index 8af36fe867efebc8332301acd6db961a7ab05867..24163c18c1073cc6b1b19eb0d9314ff70a0f46e4 100644 (file)
@@ -471,6 +471,10 @@ DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr)
                     /* snort's option */
                     pd->flags |= DETECT_PCRE_HTTP_STAT_CODE;
                     break;
+                case 'F':
+                    /* suricata extension (dns query name) */
+                    pd->flags |= DETECT_PCRE_DNS_QUERY;
+                    break;
                 default:
                     SCLogError(SC_ERR_UNKNOWN_REGEX_MOD, "unknown regex modifier '%c'", *op);
                     goto error;
@@ -693,6 +697,22 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst
         }
     }
 
+    if (pd->flags & DETECT_PCRE_DNS_QUERY) {
+        if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DNS) {
+            SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option.  "
+                       "Conflicting alprotos detected for this rule. Dns "
+                       "pcre modifier found along with a different protocol "
+                       "for the rule.");
+            goto error;
+        }
+        if (s->init_flags & (SIG_FLAG_INIT_FILE_DATA | SIG_FLAG_INIT_DCE_STUB_DATA)) {
+            SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre found with dns "
+                       "modifier set, with file_data/dce_stub_data sticky "
+                       "option set.");
+            goto error;
+        }
+    }
+
     int sm_list;
     if (s->init_flags & SIG_FLAG_INIT_FILE_DATA) {
         SCLogDebug("adding to http server body list because of file data");
@@ -766,6 +786,11 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst
         s->flags |= SIG_FLAG_APPLAYER;
         s->alproto = ALPROTO_HTTP;
         sm_list = DETECT_SM_LIST_HUADMATCH;
+    } else if (pd->flags & DETECT_PCRE_DNS_QUERY) {
+        SCLogDebug("DNS query inspection modifier set on pcre");
+        s->flags |= SIG_FLAG_APPLAYER;
+        s->alproto = ALPROTO_DNS;
+        sm_list = DETECT_SM_LIST_DNSQUERY_MATCH;
     } else {
         sm_list = DETECT_SM_LIST_PMATCH;
     }
@@ -1639,6 +1664,35 @@ int DetectPcreParseTest25(void)
     return result;
 }
 
+/** \test Check a signature with inconsistent pcre modifiers  */
+static int DetectPcreParseTest26(void)
+{
+    DetectEngineCtx *de_ctx = NULL;
+    int result = 0;
+
+    if ( (de_ctx = DetectEngineCtxInit()) == NULL)
+        goto end;
+
+    de_ctx->flags |= DE_QUIET;
+    de_ctx->sig_list = SigInit(de_ctx,
+                               "alert http any any -> any any "
+                               "(msg:\"Testing inconsistent pcre modifiers\"; "
+                               "pcre:\"/abc/F\"; sid:1;)");
+
+    if (de_ctx->sig_list == NULL) {
+        result = 1;
+    } else {
+        printf("sig parse should have failed: ");
+    }
+
+ end:
+    if (de_ctx != NULL)
+        SigCleanSignatures(de_ctx);
+    if (de_ctx != NULL)
+        DetectEngineCtxFree(de_ctx);
+    return result;
+}
+
 static int DetectPcreTestSig01Real(int mpm_type) {
     uint8_t *buf = (uint8_t *)
         "GET /one/ HTTP/1.1\r\n"
@@ -3860,6 +3914,7 @@ void DetectPcreRegisterTests(void) {
     UtRegisterTest("DetectPcreParseTest23", DetectPcreParseTest23, 1);
     UtRegisterTest("DetectPcreParseTest24", DetectPcreParseTest24, 1);
     UtRegisterTest("DetectPcreParseTest25", DetectPcreParseTest25, 1);
+    UtRegisterTest("DetectPcreParseTest26", DetectPcreParseTest26, 1);
 
     UtRegisterTest("DetectPcreTestSig01B2g -- pcre test", DetectPcreTestSig01B2g, 1);
     UtRegisterTest("DetectPcreTestSig01B3g -- pcre test", DetectPcreTestSig01B3g, 1);
index 986ca0a3d532267313a936c34432c35f26aa0f89..56c62cc3c6f47d7552ca9422fb87d964b8d917c9 100644 (file)
@@ -52,6 +52,8 @@
 #define DETECT_PCRE_NEGATE              0x80000
 #define DETECT_PCRE_CASELESS           0x100000
 
+#define DETECT_PCRE_DNS_QUERY          0x200000
+
 typedef struct DetectPcreData_ {
     /* pcre options */
     pcre *re;