]> git.ipfire.org Git - people/ms/suricata.git/commitdiff
app-layer: de_state optimization
authorVictor Julien <victor@inliniac.net>
Tue, 7 Apr 2015 14:00:08 +0000 (16:00 +0200)
committerVictor Julien <victor@inliniac.net>
Mon, 11 May 2015 10:55:27 +0000 (12:55 +0200)
Add API to bypass expensive TX list walks. This API call is optional.

Implement it for HTTP and DNS.

src/app-layer-dns-common.c
src/app-layer-dns-common.h
src/app-layer-dns-tcp.c
src/app-layer-dns-udp.c
src/app-layer-htp.c
src/app-layer-htp.h
src/app-layer-modbus.c
src/app-layer-parser.c
src/app-layer-parser.h
src/app-layer-smtp.c
src/detect-engine-state.c

index 852afa7c85dd6cae1a7be5c6c0928e78f0c534a4..b7d40425442287936e4dffb8813ec37db6fccbb5 100644 (file)
@@ -293,8 +293,11 @@ static void DNSTransactionFree(DNSTransaction *tx, DNSState *state)
 
     AppLayerDecoderEventsFreeEvents(&tx->decoder_events);
 
-    if (tx->de_state != NULL)
+    if (tx->de_state != NULL) {
         DetectEngineStateFree(tx->de_state);
+        BUG_ON(state->tx_with_detect_state_cnt == 0);
+        state->tx_with_detect_state_cnt--;
+    }
 
     if (state->iter == tx)
         state->iter = NULL;
@@ -366,15 +369,23 @@ DNSTransaction *DNSTransactionFindByTxId(const DNSState *dns_state, const uint16
     return NULL;
 }
 
+int DNSStateHasTxDetectState(void *alstate)
+{
+    DNSState *state = (DNSState *)alstate;
+    return (state->tx_with_detect_state_cnt > 0);
+}
+
 DetectEngineState *DNSGetTxDetectState(void *vtx)
 {
     DNSTransaction *tx = (DNSTransaction *)vtx;
     return tx->de_state;
 }
 
-int DNSSetTxDetectState(void *vtx, DetectEngineState *s)
+int DNSSetTxDetectState(void *alstate, void *vtx, DetectEngineState *s)
 {
+    DNSState *state = (DNSState *)alstate;
     DNSTransaction *tx = (DNSTransaction *)vtx;
+    state->tx_with_detect_state_cnt++;
     tx->de_state = s;
     return 0;
 }
@@ -413,6 +424,8 @@ void DNSStateFree(void *s)
             SCFree(dns_state->buffer);
         }
 
+        BUG_ON(dns_state->tx_with_detect_state_cnt > 0);
+
         DNSDecrMemcap(sizeof(DNSState), dns_state);
         BUG_ON(dns_state->memuse > 0);
         SCFree(s);
index 1564fec986833d30a03bdc5fc240c1bcf82534cc..1a06f8d1dc0971c3c285f47c79902ee6941adf7b 100644 (file)
@@ -181,6 +181,8 @@ typedef struct DNSState_ {
     uint32_t unreplied_cnt;                 /**< number of unreplied requests in a row */
     uint32_t memuse;                        /**< state memuse, for comparing with
                                                  state-memcap settings */
+    uint64_t tx_with_detect_state_cnt;
+
     uint16_t events;
     uint16_t givenup;
 
@@ -221,8 +223,9 @@ int DNSGetAlstateProgressCompletionStatus(uint8_t direction);
 void DNSStateTransactionFree(void *state, uint64_t tx_id);
 DNSTransaction *DNSTransactionFindByTxId(const DNSState *dns_state, const uint16_t tx_id);
 
+int DNSStateHasTxDetectState(void *alstate);
 DetectEngineState *DNSGetTxDetectState(void *vtx);
-int DNSSetTxDetectState(void *vtx, DetectEngineState *s);
+int DNSSetTxDetectState(void *alstate, void *vtx, DetectEngineState *s);
 
 void DNSSetEvent(DNSState *s, uint8_t e);
 void *DNSStateAlloc(void);
index 36b8848aeb6379b800568eeaf765258504075347..0842c6686e64cbbbe6b19f732c3bb584deb41776 100644 (file)
@@ -647,6 +647,7 @@ void RegisterDNSTCPParsers(void)
         AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_DNS, DNSGetEvents);
         AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_DNS, DNSHasEvents);
         AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_DNS,
+                                               DNSStateHasTxDetectState,
                                                DNSGetTxDetectState, DNSSetTxDetectState);
 
         AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_DNS, DNSGetTx);
index 1917914b1b11a55f60f563a0963185bcb3e52ff6..bb0c73bf555dabb26bddd6d06d24716bcae25b92 100644 (file)
@@ -403,6 +403,7 @@ void RegisterDNSUDPParsers(void)
         AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_DNS, DNSGetEvents);
         AppLayerParserRegisterHasEventsFunc(IPPROTO_UDP, ALPROTO_DNS, DNSHasEvents);
         AppLayerParserRegisterDetectStateFuncs(IPPROTO_UDP, ALPROTO_DNS,
+                                               DNSStateHasTxDetectState,
                                                DNSGetTxDetectState, DNSSetTxDetectState);
 
         AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_DNS,
index 8ae86fe1b42b809dbdef8a670f625cf5420c5cc7..2ded474ed99a579e86783cf3a4589336fd7a4913 100644 (file)
@@ -310,9 +310,9 @@ error:
     SCReturnPtr(NULL, "void");
 }
 
-static void HtpTxUserDataFree(HtpTxUserData *htud)
+static void HtpTxUserDataFree(HtpState *state, HtpTxUserData *htud)
 {
-    if (htud) {
+    if (likely(htud)) {
         HtpBodyFree(&htud->request_body);
         HtpBodyFree(&htud->response_body);
         bstr_free(htud->request_uri_normalized);
@@ -324,6 +324,11 @@ static void HtpTxUserDataFree(HtpTxUserData *htud)
         if (htud->boundary)
             HTPFree(htud->boundary, htud->boundary_len);
         if (htud->de_state != NULL) {
+            if (likely(state != NULL)) { // should be impossible that it's null
+                BUG_ON(state->tx_with_detect_state_cnt == 0);
+                state->tx_with_detect_state_cnt--;
+            }
+
             DetectEngineStateFree(htud->de_state);
         }
         HTPFree(htud, sizeof(HtpTxUserData));
@@ -357,15 +362,14 @@ void HTPStateFree(void *state)
                 htp_tx_t *tx = HTPStateGetTx(s, tx_id);
                 if (tx != NULL) {
                     HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
-                    if (htud != NULL) {
-                        HtpTxUserDataFree(htud);
-                        htp_tx_set_user_data(tx, NULL);
-                    }
+                    HtpTxUserDataFree(s, htud);
+                    htp_tx_set_user_data(tx, NULL);
                 }
             }
         }
         htp_connp_destroy_all(s->connp);
     }
+    BUG_ON(s->tx_with_detect_state_cnt > 0);
 
     FileContainerFree(s->files_ts);
     FileContainerFree(s->files_tc);
@@ -400,10 +404,8 @@ static void HTPStateTransactionFree(void *state, uint64_t id)
     if (tx != NULL) {
         /* This will remove obsolete body chunks */
         HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx);
-        if (htud != NULL) {
-            HtpTxUserDataFree(htud);
-            htp_tx_set_user_data(tx, NULL);
-        }
+        HtpTxUserDataFree(s, htud);
+        htp_tx_set_user_data(tx, NULL);
 
         htp_tx_destroy(tx);
     }
@@ -2109,10 +2111,9 @@ static int HTPCallbackRequestHeaderData(htp_tx_data_t *tx_data)
                      tx_ud->request_headers_raw_len,
                      tx_ud->request_headers_raw_len + tx_data->len);
     if (ptmp == NULL) {
-        HTPFree(tx_ud->request_headers_raw, tx_ud->request_headers_raw_len);
-        tx_ud->request_headers_raw = NULL;
-        tx_ud->request_headers_raw_len = 0;
-        HtpTxUserDataFree(tx_ud);
+        /* error: we're freeing the entire user data */
+        HtpState *hstate = htp_connp_get_user_data(tx_data->tx->connp);
+        HtpTxUserDataFree(hstate, tx_ud);
         htp_tx_set_user_data(tx_data->tx, NULL);
         return HTP_OK;
     }
@@ -2147,10 +2148,9 @@ static int HTPCallbackResponseHeaderData(htp_tx_data_t *tx_data)
                      tx_ud->response_headers_raw_len,
                      tx_ud->response_headers_raw_len + tx_data->len);
     if (ptmp == NULL) {
-        HTPFree(tx_ud->response_headers_raw, tx_ud->response_headers_raw_len);
-        tx_ud->response_headers_raw = NULL;
-        tx_ud->response_headers_raw_len = 0;
-        HtpTxUserDataFree(tx_ud);
+        /* error: we're freeing the entire user data */
+        HtpState *hstate = htp_connp_get_user_data(tx_data->tx->connp);
+        HtpTxUserDataFree(hstate, tx_ud);
         htp_tx_set_user_data(tx_data->tx, NULL);
         return HTP_OK;
     }
@@ -2635,6 +2635,12 @@ static void HTPStateTruncate(void *state, uint8_t direction)
     }
 }
 
+static int HTPStateHasTxDetectState(void *alstate)
+{
+    HtpState *htp_state = (HtpState *)alstate;
+    return (htp_state->tx_with_detect_state_cnt > 0);
+}
+
 static DetectEngineState *HTPGetTxDetectState(void *vtx)
 {
     htp_tx_t *tx = (htp_tx_t *)vtx;
@@ -2642,8 +2648,9 @@ static DetectEngineState *HTPGetTxDetectState(void *vtx)
     return tx_ud ? tx_ud->de_state : NULL;
 }
 
-static int HTPSetTxDetectState(void *vtx, DetectEngineState *s)
+static int HTPSetTxDetectState(void *alstate, void *vtx, DetectEngineState *s)
 {
+    HtpState *htp_state = (HtpState *)alstate;
     htp_tx_t *tx = (htp_tx_t *)vtx;
     HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
     if (tx_ud == NULL) {
@@ -2653,6 +2660,7 @@ static int HTPSetTxDetectState(void *vtx, DetectEngineState *s)
         memset(tx_ud, 0, sizeof(*tx_ud));
         htp_tx_set_user_data(tx, tx_ud);
     }
+    htp_state->tx_with_detect_state_cnt++;
     tx_ud->de_state = s;
     return 0;
 }
@@ -2741,6 +2749,7 @@ void RegisterHTPParsers(void)
 
         AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPStateTruncate);
         AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_HTTP,
+                                               HTPStateHasTxDetectState,
                                                HTPGetTxDetectState, HTPSetTxDetectState);
 
         AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_HTTP, STREAM_TOSERVER,
index 869d2bfc221c90c9ce6840e46c4878d5a466127f..50b95d66d1a01d7b42b546ca3dc19ffea44d7e01 100644 (file)
@@ -248,6 +248,7 @@ typedef struct HtpState_ {
     uint16_t flags;
     uint16_t events;
     uint16_t htp_messages_offset; /**< offset into conn->messages list */
+    uint64_t tx_with_detect_state_cnt;
 } HtpState;
 
 /** part of the engine needs the request body (e.g. http_client_body keyword) */
index 31982eadfe8cf210441de7f682177b7accaad5c8..93b834b4b3d20d2e5c71231ea4d7d95ab66e7bcf 100644 (file)
@@ -1343,7 +1343,7 @@ DetectEngineState *ModbusGetTxDetectState(void *vtx)
     return tx->de_state;
 }
 
-int ModbusSetTxDetectState(void *vtx, DetectEngineState *s)
+int ModbusSetTxDetectState(void *state, void *vtx, DetectEngineState *s)
 {
     ModbusTransaction *tx = (ModbusTransaction *)vtx;
     tx->de_state = s;
@@ -1410,7 +1410,7 @@ void RegisterModbusParsers(void)
 
         AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetEvents);
         AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusHasEvents);
-        AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_MODBUS,
+        AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_MODBUS, NULL,
                                                ModbusGetTxDetectState, ModbusSetTxDetectState);
 
         AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetTx);
index 42ad4e1eddc6a10315f7bc3fbf6f99181fbb84e4..289a59d7cd442021fa8de4567c50b7cc83be0c35 100644 (file)
@@ -106,8 +106,9 @@ typedef struct AppLayerParserProtoCtx_
     int (*StateGetEventInfo)(const char *event_name,
                              int *event_id, AppLayerEventType *event_type);
 
+    int (*StateHasTxDetectState)(void *alstate);
     DetectEngineState *(*GetTxDetectState)(void *tx);
-    int (*SetTxDetectState)(void *tx, DetectEngineState *);
+    int (*SetTxDetectState)(void *alstate, void *tx, DetectEngineState *);
 
     /* Indicates the direction the parser is ready to see the data
      * the first time for a flow.  Values accepted -
@@ -472,11 +473,13 @@ void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto,
 }
 
 void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto,
+        int (*StateHasTxDetectState)(void *alstate),
         DetectEngineState *(*GetTxDetectState)(void *tx),
-        int (*SetTxDetectState)(void *tx, DetectEngineState *))
+        int (*SetTxDetectState)(void *alstate, void *tx, DetectEngineState *))
 {
     SCEnter();
 
+    alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateHasTxDetectState = StateHasTxDetectState;
     alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState = GetTxDetectState;
     alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectState = SetTxDetectState;
 
@@ -804,6 +807,16 @@ int AppLayerParserSupportsTxDetectState(uint8_t ipproto, AppProto alproto)
     return FALSE;
 }
 
+int AppLayerParserHasTxDetectState(uint8_t ipproto, AppProto alproto, void *alstate)
+{
+    int r;
+    SCEnter();
+    if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateHasTxDetectState == NULL)
+        return -ENOSYS;
+    r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateHasTxDetectState(alstate);
+    SCReturnInt(r);
+}
+
 DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx)
 {
     SCEnter();
@@ -812,13 +825,14 @@ DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alpr
     SCReturnPtr(s, "DetectEngineState");
 }
 
-int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx, DetectEngineState *s)
+int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto,
+                                   void *alstate, void *tx, DetectEngineState *s)
 {
     int r;
     SCEnter();
     if ((alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState(tx) != NULL))
         SCReturnInt(-EBUSY);
-    r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectState(tx, s);
+    r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectState(alstate, tx, s);
     SCReturnInt(r);
 }
 
index 44f27b76c8d2205d087ceae1008bcfa7558c9b53..b81459b7666a6dca3b4194a83c9fde299a72c128 100644 (file)
@@ -143,8 +143,9 @@ void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto,
     int (*StateGetEventInfo)(const char *event_name, int *event_id,
                              AppLayerEventType *event_type));
 void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto,
+        int (*StateHasTxDetectState)(void *alstate),
         DetectEngineState *(*GetTxDetectState)(void *tx),
-        int (*SetTxDetectState)(void *tx, DetectEngineState *));
+        int (*SetTxDetectState)(void *alstate, void *tx, DetectEngineState *));
 
 /***** Get and transaction functions *****/
 
@@ -180,8 +181,9 @@ uint64_t AppLayerParserGetTransactionActive(uint8_t ipproto, AppProto alproto, A
 uint8_t AppLayerParserGetFirstDataDir(uint8_t ipproto, AppProto alproto);
 
 int AppLayerParserSupportsTxDetectState(uint8_t ipproto, AppProto alproto);
+int AppLayerParserHasTxDetectState(uint8_t ipproto, AppProto alproto, void *alstate);
 DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx);
-int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx, DetectEngineState *s);
+int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, void *alstate, void *tx, DetectEngineState *s);
 
 /***** General *****/
 
index e03cad89470c2d1f117c8043c738bf6cbe0a0f2b..c0772ec75ae4a0c00196ea2231a5a7f1827a67cf 100644 (file)
@@ -1381,7 +1381,7 @@ static DetectEngineState *SMTPGetTxDetectState(void *vtx)
     return tx->de_state;
 }
 
-static int SMTPSetTxDetectState(void *vtx, DetectEngineState *s)
+static int SMTPSetTxDetectState(void *state, void *vtx, DetectEngineState *s)
 {
     SMTPTransaction *tx = (SMTPTransaction *)vtx;
     tx->de_state = s;
@@ -1415,7 +1415,7 @@ void RegisterSMTPParsers(void)
 
         AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo);
         AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetEvents);
-        AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SMTP,
+        AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, NULL,
                                                SMTPGetTxDetectState, SMTPSetTxDetectState);
 
         AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc,
index 150f492136144571c861763b61948f0cab7f2aec..37a63f5c7fad20cf54d13e20c8aa7d38dea2d882 100644 (file)
@@ -335,6 +335,14 @@ static int HasStoredSigs(Flow *f, uint8_t flags)
             return 0;
         }
 
+        int state = AppLayerParserHasTxDetectState(f->proto, alproto, f->alstate);
+        if (state == -ENOSYS) { /* proto doesn't support this API call */
+            /* fall through */
+        } else if (state == 0) {
+            return 0;
+        }
+        /* if state == 1 we also fall through */
+
         uint64_t inspect_tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags);
         uint64_t total_txs = AppLayerParserGetTxCnt(f->proto, alproto, alstate);
 
@@ -423,7 +431,7 @@ static void StoreStateTxFileOnly(DetectEngineThreadCtx *det_ctx,
             destate = DetectEngineStateAlloc();
             if (destate == NULL)
                 return;
-            if (AppLayerParserSetTxDetectState(f->proto, f->alproto, tx, destate) < 0) {
+            if (AppLayerParserSetTxDetectState(f->proto, f->alproto, f->alstate, tx, destate) < 0) {
                 DetectEngineStateFree(destate);
                 BUG_ON(1);
                 return;
@@ -449,7 +457,7 @@ static void StoreStateTx(DetectEngineThreadCtx *det_ctx,
             destate = DetectEngineStateAlloc();
             if (destate == NULL)
                 return;
-            if (AppLayerParserSetTxDetectState(f->proto, f->alproto, tx, destate) < 0) {
+            if (AppLayerParserSetTxDetectState(f->proto, f->alproto, f->alstate, tx, destate) < 0) {
                 DetectEngineStateFree(destate);
                 BUG_ON(1);
                 return;