]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
XFF: use per alert tx id
authorVictor Julien <victor@inliniac.net>
Wed, 18 Sep 2013 13:09:38 +0000 (15:09 +0200)
committerVictor Julien <victor@inliniac.net>
Tue, 8 Oct 2013 14:40:43 +0000 (16:40 +0200)
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.

src/alert-unified2-alert.c

index daa12ccb04fab084771544d30e34615506af9a89..bd9338930562393f53279940b279eb9b67c056c5 100644 (file)
@@ -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;