From e8ad876b481dcf1f919e0077ce028fbe3421b1e6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 1 Jul 2013 15:24:50 +0200 Subject: [PATCH] App layer: add 'StateHasEvents' API call Per TX decoder events resulted in significant overhead to the detection engine, as it walked all TX' all the time to check if decoder events were available. This commit introduces a new API call StateHasEvents, which speeds up this process, at the expense of keeping a counter in the state. Implement this for DNS as well. --- src/app-layer-dns-common.c | 14 ++++++++++++++ src/app-layer-dns-common.h | 3 ++- src/app-layer-dns-tcp.c | 3 ++- src/app-layer-dns-udp.c | 3 ++- src/app-layer-parser.c | 29 +++++++++++++++++++++-------- src/app-layer-parser.h | 5 +++++ 6 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 84f944e06a..949d32e318 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -45,6 +45,11 @@ void DNSAppLayerDecoderEventsRegister(int alproto) { AppLayerDecoderEvents *DNSGetEvents(void *state, uint64_t id) { DNSState *dns_state = (DNSState *)state; DNSTransaction *tx; + + if (dns_state->curr && dns_state->curr->tx_num == (id + 1)) { + return dns_state->curr->decoder_events; + } + TAILQ_FOREACH(tx, &dns_state->tx_list, next) { if (tx->tx_num == (id+1)) return tx->decoder_events; @@ -52,6 +57,11 @@ AppLayerDecoderEvents *DNSGetEvents(void *state, uint64_t id) { return NULL; } +int DNSHasEvents(void *state) { + DNSState *dns_state = (DNSState *)state; + return (dns_state->events > 0); +} + void *DNSStateAlloc(void) { void *s = SCMalloc(sizeof(DNSState)); if (unlikely(s == NULL)) @@ -87,6 +97,9 @@ void *DNSGetTx(void *alstate, uint64_t tx_id) { DNSState *dns_state = (DNSState *)alstate; DNSTransaction *tx = NULL; + if (dns_state->curr && dns_state->curr->tx_num == tx_id + 1) + return dns_state->curr; + TAILQ_FOREACH(tx, &dns_state->tx_list, next) { SCLogDebug("tx->tx_num %u, tx_id %"PRIu64, tx->tx_num, (tx_id+1)); if ((tx_id+1) != tx->tx_num) @@ -119,6 +132,7 @@ void DNSSetEvent(DNSState *s, uint8_t e) { SCLogDebug("s->curr->decoder_events %p", s->curr->decoder_events); AppLayerDecoderEventsSetEventRaw(s->curr->decoder_events, e); SCLogDebug("s->curr->decoder_events %p", s->curr->decoder_events); + s->events++; } else { SCLogDebug("couldn't set event %u", e); } diff --git a/src/app-layer-dns-common.h b/src/app-layer-dns-common.h index 3d899e4957..25c9896ef2 100644 --- a/src/app-layer-dns-common.h +++ b/src/app-layer-dns-common.h @@ -142,7 +142,7 @@ typedef struct DNSState_ { TAILQ_HEAD(, DNSTransaction_) tx_list; /**< transaction list */ DNSTransaction *curr; /**< ptr to current tx */ uint16_t transaction_max; - uint16_t transaction_done; + uint16_t events; /* used by TCP only */ uint16_t offset; @@ -168,6 +168,7 @@ void DNSSetEvent(DNSState *s, uint8_t e); void *DNSStateAlloc(void); void DNSStateFree(void *s); AppLayerDecoderEvents *DNSGetEvents(void *state, uint64_t id); +int DNSHasEvents(void *state); int DNSValidateRequestHeader(DNSState *, const DNSHeader *dns_header); int DNSValidateResponseHeader(DNSState *, const DNSHeader *dns_header); diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index 73602dfee5..dd0611a1e4 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -603,7 +603,6 @@ void DNSStateTransactionFree(void *state, uint16_t id) { DNSState *s = state; - s->transaction_done = id; SCLogDebug("state %p, id %"PRIu16, s, id); /* we can't remove the actual transactions here */ @@ -624,7 +623,9 @@ void RegisterDNSTCPParsers(void) { DNSStateFree); AppLayerRegisterTransactionIdFuncs(ALPROTO_DNS_TCP, DNSStateUpdateTransactionId, DNSStateTransactionFree); + AppLayerRegisterGetEventsFunc(ALPROTO_DNS_TCP, DNSGetEvents); + AppLayerRegisterHasEventsFunc(ALPROTO_DNS_TCP, DNSHasEvents); AppLayerRegisterGetTx(ALPROTO_DNS_TCP, DNSGetTx); diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index 253ec16836..f73d57265b 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -324,7 +324,6 @@ static void DNSStateTransactionFree(void *state, uint16_t id) { DNSState *s = state; - s->transaction_done = id; SCLogDebug("state %p, id %"PRIu16, s, id); /* we can't remove the actual transactions here */ @@ -345,7 +344,9 @@ void RegisterDNSUDPParsers(void) { DNSStateFree); AppLayerRegisterTransactionIdFuncs(ALPROTO_DNS_UDP, DNSStateUpdateTransactionId, DNSStateTransactionFree); + AppLayerRegisterGetEventsFunc(ALPROTO_DNS_UDP, DNSGetEvents); + AppLayerRegisterHasEventsFunc(ALPROTO_DNS_UDP, DNSHasEvents); AppLayerRegisterGetTx(ALPROTO_DNS_UDP, DNSGetTx); diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 1e3c180e41..c919e75c4e 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -121,10 +121,11 @@ AppLayerDecoderEvents *AppLayerGetEventsFromFlowByTx(Flow *f, uint64_t tx_id) { } } -/** \brief check if we have decoder events */ +/** \brief check if we have decoder events + * \retval 1 yes + * \retval 0 no */ int AppLayerFlowHasDecoderEvents(Flow *f, uint8_t flags) { AppLayerDecoderEvents *decoder_events; - uint64_t tx_id, max_id; DEBUG_ASSERT_FLOW_LOCKED(f); @@ -132,13 +133,20 @@ int AppLayerFlowHasDecoderEvents(Flow *f, uint8_t flags) { return 0; if (AppLayerProtoIsTxEventAware(f->alproto)) { - tx_id = AppLayerTransactionGetInspectId(f, flags); - max_id = AppLayerGetTxCnt(f->alproto, f->alstate); - - for ( ; tx_id < max_id; tx_id++) { - decoder_events = AppLayerGetEventsFromFlowByTx(f, tx_id); - if (decoder_events && decoder_events->cnt) + /* fast path if supported by proto */ + if (al_proto_table[f->alproto].StateHasEvents != NULL) { + if (al_proto_table[f->alproto].StateHasEvents(f->alstate) == 1) return 1; + } else { + /* check each tx */ + uint64_t tx_id = AppLayerTransactionGetInspectId(f, flags); + uint64_t max_id = AppLayerGetTxCnt(f->alproto, f->alstate); + + for ( ; tx_id < max_id; tx_id++) { + decoder_events = AppLayerGetEventsFromFlowByTx(f, tx_id); + if (decoder_events && decoder_events->cnt) + return 1; + } } } @@ -802,6 +810,11 @@ void AppLayerRegisterGetEventsFunc(uint16_t proto, al_proto_table[proto].StateGetEvents = StateGetEvents; } +void AppLayerRegisterHasEventsFunc(uint16_t proto, + int (*StateHasEvents)(void *)) { + al_proto_table[proto].StateHasEvents = StateHasEvents; +} + /** \brief Indicate to the app layer parser that a logger is active * for this protocol. */ diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index 81c53c7304..9a949c1a79 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -59,6 +59,8 @@ typedef struct AppLayerProto_ { void (*Truncate)(void *, uint8_t); FileContainer *(*StateGetFiles)(void *, uint8_t); AppLayerDecoderEvents *(*StateGetEvents)(void *, uint64_t); + /* bool indicating a state has decoder/parser events */ + int (*StateHasEvents)(void *); int (*StateGetAlstateProgress)(void *alstate, uint8_t direction); uint64_t (*StateGetTxCnt)(void *alstate); @@ -261,6 +263,9 @@ void AppLayerRegisterGetFilesFunc(uint16_t proto, FileContainer *(*StateGetFile)(void *, uint8_t)); void AppLayerRegisterGetEventsFunc(uint16_t proto, AppLayerDecoderEvents *(*StateGetEvents)(void *, uint64_t)); +void AppLayerRegisterHasEventsFunc(uint16_t proto, + int (*StateHasEvents)(void *)); + void AppLayerRegisterLogger(uint16_t proto); uint16_t AppLayerGetProtoByName(const char *); const char *AppLayerGetProtoString(int proto);