From: Victor Julien Date: Wed, 18 Sep 2013 13:09:38 +0000 (+0200) Subject: XFF: use per alert tx id X-Git-Tag: suricata-2.0beta2~232 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1d18155a169418e129ffad1dbb2a764a98fd41e3;p=thirdparty%2Fsuricata.git XFF: use per alert tx id Use the tx id stored for each alert to find the correct XFF address to add to the extra-data field. In overwrite mode we still only grab the first available XFF addr, as this address is set in the header preceeding the individual alerts. Issue #904. --- diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index daa12ccb04..bd93389305 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -315,61 +315,79 @@ static int Unified2Write(Unified2AlertThread *aun) return 1; } -/** - * \brief Function to return XFF IP if any... - * \retval 1 if the IP has been found and returned in dstbuf - * \retval 0 if the IP has not being found or error - */ -static int GetXFFIP (Packet *p, char *xff_header, char *dstbuf, int dstbuflen) +static int GetXFFIPFromTx (Packet *p, uint64_t tx_id, char *xff_header, char *dstbuf, int dstbuflen) { uint8_t xff_chain[UNIFIED2_ALERT_XFF_CHAIN_MAXLEN]; HtpState *htp_state = NULL; htp_tx_t *tx = NULL; - uint64_t tx_id = 0; uint64_t total_txs = 0; htp_state = (HtpState *)AppLayerGetProtoStateFromPacket(p); if (htp_state == NULL) { SCLogDebug("no http state, XFF IP cannot be retrieved"); - goto end; + return 0; } total_txs = AppLayerGetTxCnt(ALPROTO_HTTP, htp_state); + if (tx_id >= total_txs) + return 0; - for (; tx_id < total_txs; tx_id++) { - tx = AppLayerGetTx(ALPROTO_HTTP, htp_state, tx_id); + tx = AppLayerGetTx(ALPROTO_HTTP, htp_state, tx_id); + if (tx == NULL) { + SCLogDebug("tx is NULL, XFF cannot be retrieved"); + return 0; + } - if (tx == NULL) { - SCLogDebug("tx is NULL, XFF cannot be retrieved"); - continue; - } + htp_header_t *h_xff = NULL; + if (tx->request_headers != NULL) { + h_xff = htp_table_get_c(tx->request_headers, xff_header); + } + + if (h_xff != NULL && bstr_len(h_xff->value) >= UNIFIED2_ALERT_XFF_CHAIN_MINLEN && + bstr_len(h_xff->value) < UNIFIED2_ALERT_XFF_CHAIN_MAXLEN) { - htp_header_t *h_xff = NULL; - if (tx->request_headers != NULL) { - h_xff = htp_table_get_c(tx->request_headers, xff_header); + memcpy(xff_chain, bstr_ptr(h_xff->value), bstr_len(h_xff->value)); + xff_chain[bstr_len(h_xff->value)]=0; + /** Check for chained IP's separated by ", ", we will get the last one */ + uint8_t *p_xff = memrchr(xff_chain, ' ', bstr_len(h_xff->value)); + if (p_xff == NULL) { + p_xff = xff_chain; + } else { + p_xff++; + } + /** Sanity check on extracted IP for IPv4 and IPv6 */ + uint32_t ip[4]; + if ( inet_pton(AF_INET, (char *)p_xff, ip ) == 1 || + inet_pton(AF_INET6, (char *)p_xff, ip ) == 1 ) { + strlcpy(dstbuf, (char *)p_xff, dstbuflen); + return 1; // OK } + } + return 0; +} - if (h_xff != NULL && bstr_len(h_xff->value) >= UNIFIED2_ALERT_XFF_CHAIN_MINLEN && - bstr_len(h_xff->value) < UNIFIED2_ALERT_XFF_CHAIN_MAXLEN) { +/** + * \brief Function to return XFF IP if any... + * \retval 1 if the IP has been found and returned in dstbuf + * \retval 0 if the IP has not being found or error + */ +static int GetXFFIP (Packet *p, char *xff_header, char *dstbuf, int dstbuflen) +{ + HtpState *htp_state = NULL; + uint64_t tx_id = 0; + uint64_t total_txs = 0; - memcpy(xff_chain, bstr_ptr(h_xff->value), bstr_len(h_xff->value)); - xff_chain[bstr_len(h_xff->value)]=0; - /** Check for chained IP's separated by ", ", we will get the last one */ - uint8_t *p_xff = memrchr(xff_chain, ' ', bstr_len(h_xff->value)); - if (p_xff == NULL) { - p_xff = xff_chain; - } else { - p_xff++; - } - /** Sanity check on extracted IP for IPv4 and IPv6 */ - uint32_t ip[4]; - if ( inet_pton(AF_INET, (char *)p_xff, ip ) == 1 || - inet_pton(AF_INET6, (char *)p_xff, ip ) == 1 ) { - strlcpy(dstbuf, (char *)p_xff, dstbuflen); - return 1; // OK - } - } + htp_state = (HtpState *)AppLayerGetProtoStateFromPacket(p); + if (htp_state == NULL) { + SCLogDebug("no http state, XFF IP cannot be retrieved"); + goto end; + } + + total_txs = AppLayerGetTxCnt(ALPROTO_HTTP, htp_state); + for (; tx_id < total_txs; tx_id++) { + if (GetXFFIPFromTx(p, tx_id, xff_header, dstbuf, dstbuflen) == 1) + return 1; } end: @@ -384,14 +402,16 @@ end: */ TmEcode Unified2Alert (ThreadVars *t, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { + int ret = 0; Unified2AlertThread *aun = (Unified2AlertThread *)data; aun->xff_flags = UNIFIED2_ALERT_XFF_DISABLED; if (p->alerts.cnt == 0 && !(p->flags & PKT_HAS_TAG)) return TM_ECODE_OK; - if (!(aun->unified2alert_ctx->xff_mode & UNIFIED2_ALERT_XFF_DISABLED) && - p->flow != NULL) { + /* overwrite mode can only work per u2 block, not per individual + * alert. So we'll look for an XFF record once */ + if ((aun->unified2alert_ctx->xff_mode & UNIFIED2_ALERT_XFF_OVERWRITE) && p->flow != NULL) { FLOWLOCK_RDLOCK(p->flow); if (AppLayerGetProtoFromPacket(p) == ALPROTO_HTTP) { @@ -401,34 +421,20 @@ TmEcode Unified2Alert (ThreadVars *t, Packet *p, void *data, PacketQueue *pq, Pa /** Be sure that we have a nice zeroed buffer */ memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); - if (aun->unified2alert_ctx->xff_mode & UNIFIED2_ALERT_XFF_OVERWRITE) { - /** We can only have override mode if packet IP version matches - * the XFF IP version, otherwise fall-back to extra data */ - if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { - aun->xff_flags = UNIFIED2_ALERT_XFF_IPV4; - - if (PKT_IS_IPV4(p)) { - aun->xff_flags |= UNIFIED2_ALERT_XFF_OVERWRITE; - } else { - aun->xff_flags |= UNIFIED2_ALERT_XFF_EXTRADATA; - } - } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { - aun->xff_flags = UNIFIED2_ALERT_XFF_IPV6; - - if (PKT_IS_IPV6(p)) { - aun->xff_flags |= UNIFIED2_ALERT_XFF_OVERWRITE; - } else { - aun->xff_flags |= UNIFIED2_ALERT_XFF_EXTRADATA; - } + /** We can only have override mode if packet IP version matches + * the XFF IP version, otherwise fall-back to extra data */ + if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { + SCLogDebug("valid ipv4 xff, setting flags %s", buffer); + if (PKT_IS_IPV4(p)) { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|UNIFIED2_ALERT_XFF_OVERWRITE); + } else { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|UNIFIED2_ALERT_XFF_EXTRADATA); } - } - else if (aun->unified2alert_ctx->xff_mode & UNIFIED2_ALERT_XFF_EXTRADATA) { - aun->xff_flags = UNIFIED2_ALERT_XFF_EXTRADATA; - - if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { - aun->xff_flags |= UNIFIED2_ALERT_XFF_IPV4; - } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { - aun->xff_flags |= UNIFIED2_ALERT_XFF_IPV6; + } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { + if (PKT_IS_IPV6(p)) { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|UNIFIED2_ALERT_XFF_OVERWRITE); + } else { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|UNIFIED2_ALERT_XFF_EXTRADATA); } } } @@ -436,8 +442,6 @@ TmEcode Unified2Alert (ThreadVars *t, Packet *p, void *data, PacketQueue *pq, Pa FLOWLOCK_UNLOCK(p->flow); } - int ret = 0; - if (PKT_IS_IPV4(p)) { ret = Unified2IPv4TypeAlert (t, p, data, pq); } else if(PKT_IS_IPV6(p)) { @@ -962,6 +966,31 @@ int Unified2IPv6TypeAlert (ThreadVars *t, Packet *p, void *data, PacketQueue *pq if (unlikely(pa->s == NULL)) continue; + if ((aun->unified2alert_ctx->xff_mode & UNIFIED2_ALERT_XFF_EXTRADATA) && p->flow != NULL) { + FLOWLOCK_RDLOCK(p->flow); + if (AppLayerGetProtoFromPacket(p) == ALPROTO_HTTP) { + char buffer[UNIFIED2_ALERT_XFF_MAXLEN]; + int have_xff_ip = 0; + + if (pa->flags & PACKET_ALERT_FLAG_TX) { + have_xff_ip = GetXFFIPFromTx(p, pa->tx_id, aun->unified2alert_ctx->xff_header, buffer, UNIFIED2_ALERT_XFF_MAXLEN); + } else { + have_xff_ip = GetXFFIP(p, aun->unified2alert_ctx->xff_header, buffer, UNIFIED2_ALERT_XFF_MAXLEN); + } + if (have_xff_ip) { + memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); + + if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { + SCLogDebug("valid ipv4 xff, setting flag"); + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|UNIFIED2_ALERT_XFF_EXTRADATA); + } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|UNIFIED2_ALERT_XFF_EXTRADATA); + } + } + } + FLOWLOCK_UNLOCK(p->flow); + } + /* reset length and offset */ aun->offset = offset; aun->length = length; @@ -1111,6 +1140,32 @@ int Unified2IPv4TypeAlert (ThreadVars *tv, Packet *p, void *data, PacketQueue *p if (unlikely(pa->s == NULL)) continue; + if ((aun->unified2alert_ctx->xff_mode & UNIFIED2_ALERT_XFF_EXTRADATA) && p->flow != NULL) { + FLOWLOCK_RDLOCK(p->flow); + if (AppLayerGetProtoFromPacket(p) == ALPROTO_HTTP) { + char buffer[UNIFIED2_ALERT_XFF_MAXLEN]; + int have_xff_ip = 0; + + if (pa->flags & PACKET_ALERT_FLAG_TX) { + have_xff_ip = GetXFFIPFromTx(p, pa->tx_id, aun->unified2alert_ctx->xff_header, buffer, UNIFIED2_ALERT_XFF_MAXLEN); + } else { + have_xff_ip = GetXFFIP(p, aun->unified2alert_ctx->xff_header, buffer, UNIFIED2_ALERT_XFF_MAXLEN); + } + if (have_xff_ip) { + SCLogDebug("buffer %s", buffer); + memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); + + if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { + SCLogDebug("valid ipv4 xff, setting flags %s", buffer); + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|UNIFIED2_ALERT_XFF_EXTRADATA); + } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|UNIFIED2_ALERT_XFF_EXTRADATA); + } + } + } + FLOWLOCK_UNLOCK(p->flow); + } + /* reset length and offset */ aun->offset = offset; aun->length = length;