]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
unified2: big rewrite to clean up code that deals with tcp segment logging.
authorVictor Julien <victor@inliniac.net>
Wed, 30 May 2012 13:27:16 +0000 (15:27 +0200)
committerVictor Julien <victor@inliniac.net>
Wed, 30 May 2012 14:22:33 +0000 (16:22 +0200)
src/alert-unified2-alert.c

index edcb59e9f46451cc23b56b5a005d24043bcf1511..40008b0fbb569bb8ff94da40fda53dd53fa5189b 100644 (file)
@@ -159,6 +159,7 @@ typedef struct Unified2AlertThread_ {
     int datalen; /**< Length of per function and thread data */
     int offset; /**< Offset used to now where to fill data */
     int length; /**< Length of data for current alert */
+    uint32_t event_id;
 } Unified2AlertThread;
 
 #define UNIFIED2_PACKET_SIZE        (sizeof(Unified2Packet) - 4)
@@ -311,11 +312,14 @@ typedef struct _FakeIPv6Hdr {
     TCPHdr tcph;
 } FakeIPv6Hdr;
 
-static int Unified2ForgeFakeIPv6Header(FakeIPv6Hdr *fakehdr, Packet *p, int pkt_len, char invert)
+/**
+ *  \param payload_len length of the payload
+ */
+static int Unified2ForgeFakeIPv6Header(FakeIPv6Hdr *fakehdr, Packet *p, int payload_len, char invert)
 {
     fakehdr->ip6h.s_ip6_vfc = p->ip6h->s_ip6_vfc;
     fakehdr->ip6h.s_ip6_nxt = IPPROTO_TCP;
-    fakehdr->ip6h.s_ip6_plen = htons(sizeof(TCPHdr));
+    fakehdr->ip6h.s_ip6_plen = htons(sizeof(TCPHdr) + payload_len);
     if (!invert) {
         memcpy(fakehdr->ip6h.s_ip6_addrs, p->ip6h->s_ip6_addrs, 32);
     } else {
@@ -341,33 +345,119 @@ static int Unified2PrintStreamSegmentCallback(Packet *p, void *data, uint8_t *bu
 {
     int ret = 1;
     Unified2AlertThread *aun = (Unified2AlertThread *)data;
+    Unified2AlertFileHeader *hdr = (Unified2AlertFileHeader*)(aun->data);
+    Unified2Packet *phdr = (Unified2Packet *)(hdr + 1);
+    int ethh_offset = 0;
+    EthernetHdr ethhdr = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, htons(ETHERNET_TYPE_IPV6) };
     uint32_t hdr_length = 0;
-    uint32_t orig_length = aun->length;
+    int datalink = p->datalink;
 
-    if (PKT_IS_IPV6(p)) {
-        FakeIPv6Hdr *fakehdr = (FakeIPv6Hdr *)aun->iphdr;
+    memset(hdr, 0, sizeof(Unified2AlertFileHeader));
+    memset(phdr, 0, sizeof(Unified2Packet));
+
+    hdr->type = htonl(UNIFIED2_PACKET_TYPE);
+    aun->hdr = hdr;
+
+    phdr->sensor_id = 0;
+    phdr->linktype = htonl(datalink);
+    phdr->event_id = aun->event_id;
+    phdr->event_second = phdr->packet_second = htonl(p->ts.tv_sec);
+    phdr->packet_microsecond = htonl(p->ts.tv_usec);
+    aun->phdr = phdr;
+
+    if (p->datalink != DLT_EN10MB) {
+        /* We have raw data here */
+        phdr->linktype = htonl(DLT_RAW);
+        datalink = DLT_RAW;
+    }
+
+    aun->length = sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE;
+    aun->offset = sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE;
+
+    /* Include Packet header */
+    if (PKT_IS_IPV4(p)) {
+        FakeIPv4Hdr fakehdr;
+        hdr_length = sizeof(FakeIPv4Hdr);
+
+        if (p->datalink == DLT_EN10MB) {
+            /* Fake this */
+            ethh_offset = 14;
+            datalink = DLT_EN10MB;
+            phdr->linktype = htonl(datalink);
+            aun->length += ethh_offset;
+
+            if (aun->length > aun->datalen) {
+                SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data");
+                goto error;
+            }
+            ethhdr.eth_type = htons(ETHERNET_TYPE_IP);
+
+            memcpy(aun->data + aun->offset, &ethhdr, 14);
+            aun->offset += ethh_offset;
+        }
+
+        memset(&fakehdr, 0, hdr_length);
+        aun->length += hdr_length;
+        Unified2ForgeFakeIPv4Header(&fakehdr, p, hdr_length + buflen, 0);
+        if (aun->length > aun->datalen) {
+            SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data");
+            goto error;
+        }
+        memcpy(aun->data + aun->offset, &fakehdr, hdr_length);
+        aun->iphdr = (void *)(aun->data + aun->offset);
+        aun->offset += hdr_length;
+
+    } else if (PKT_IS_IPV6(p)) {
+        FakeIPv6Hdr fakehdr;
         hdr_length = sizeof(FakeIPv6Hdr);
-        fakehdr->ip6h.s_ip6_plen = htons((uint16_t) (hdr_length + buflen));
+
+        if (p->datalink == DLT_EN10MB) {
+            /* Fake this */
+            ethh_offset = 14;
+            datalink = DLT_EN10MB;
+            phdr->linktype = htonl(datalink);
+            aun->length += ethh_offset;
+            if (aun->length > aun->datalen) {
+                SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data");
+                goto error;
+            }
+            ethhdr.eth_type = htons(ETHERNET_TYPE_IPV6);
+
+            memcpy(aun->data + aun->offset, &ethhdr, 14);
+            aun->offset += ethh_offset;
+        }
+
+        memset(&fakehdr, 0, hdr_length);
+        Unified2ForgeFakeIPv6Header(&fakehdr, p, buflen, 1);
+
+        aun->length += hdr_length;
+        if (aun->length > aun->datalen) {
+            SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data");
+            goto error;
+        }
+        memcpy(aun->data + aun->offset, &fakehdr, hdr_length);
+        aun->iphdr = (void *)(aun->data + aun->offset);
+        aun->offset += hdr_length;
     } else {
-        FakeIPv4Hdr *fakehdr = (FakeIPv4Hdr *)aun->iphdr;
-        hdr_length = sizeof(FakeIPv4Hdr);
-        fakehdr->ip4h.ip_len = htons((uint16_t) (hdr_length + buflen));
+        goto error;
     }
 
-    aun->hdr->length = htonl(UNIFIED2_PACKET_SIZE +
-            ((p->datalink == DLT_EN10MB) ? 14 : 0) +
-            buflen + hdr_length);
-    aun->phdr->packet_length = htonl(buflen + hdr_length +
-            ((p->datalink == DLT_EN10MB) ? 14 : 0));
+    /* update unified2 headers for length */
+    aun->hdr->length = htonl(UNIFIED2_PACKET_SIZE + ethh_offset +
+            hdr_length + buflen);
+    aun->phdr->packet_length = htonl(ethh_offset + hdr_length + buflen);
 
+    /* copy stream segment payload in */
     aun->length += buflen;
+
     if (aun->length > aun->datalen) {
         SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread"
                    " data: %d vs %d", aun->length, aun->datalen);
-        aun->length = orig_length;
-        return -1;
+        goto error;
     }
+
     memcpy(aun->data + aun->offset, buf, buflen);
+    aun->offset += buflen;
 
     /* rebuild checksum */
     if (PKT_IS_IPV6(p)) {
@@ -384,12 +474,17 @@ static int Unified2PrintStreamSegmentCallback(Packet *p, void *data, uint8_t *bu
                 IPV4_GET_RAW_HLEN(&fakehdr->ip4h));
     }
 
+    /* write out */
     ret = Unified2Write(aun);
     if (ret != 1) {
-        aun->length = orig_length;
-        return ret;
+        goto error;
     }
-    return ret;
+    return 1;
+
+error:
+    aun->length = 0;
+    aun->offset = 0;
+    return -1;
 }
 
 
@@ -406,43 +501,21 @@ static int Unified2PrintStreamSegmentCallback(Packet *p, void *data, uint8_t *bu
  *  \param aun thread local data
  *  \param p Packet
  *  \param stream pointer to stream chunk
+ *  \param event_id unique event id
+ *  \param stream state/stream match, try logging stream segments
  *
  *  \retval 0 on succces
  *  \retval -1 on failure
  */
-int Unified2PacketTypeAlert (Unified2AlertThread *aun, Packet *p, uint32_t event_id, int state)
+int Unified2PacketTypeAlert (Unified2AlertThread *aun, Packet *p, uint32_t event_id, int stream)
 {
-    Unified2AlertFileHeader *hdr = (Unified2AlertFileHeader*)(aun->data + aun->offset);
-    Unified2Packet *phdr = (Unified2Packet *)(hdr + 1);
     int ret = 0;
-    int len = aun->offset + (sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE);
-    int datalink = p->datalink;
-    int ethh_offset = 0;
-    EthernetHdr ethhdr = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, htons(ETHERNET_TYPE_IPV6) };
-
-    memset(hdr, 0, sizeof(Unified2AlertFileHeader));
-    memset(phdr, 0, sizeof(Unified2Packet));
 
-    hdr->type = htonl(UNIFIED2_PACKET_TYPE);
-    aun->hdr = hdr;
-
-    phdr->sensor_id = 0;
-    phdr->linktype = htonl(datalink);
-    phdr->event_id =  event_id;
-    phdr->event_second = phdr->packet_second = htonl(p->ts.tv_sec);
-    phdr->packet_microsecond = htonl(p->ts.tv_usec);
-    aun->phdr = phdr;
-
-    if (state) {
+    /* try stream logging first */
+    if (stream) {
         SCLogDebug("logging the state");
         uint8_t flag;
 
-        if (p->datalink != DLT_EN10MB) {
-            /* We have raw data here */
-            phdr->linktype = htonl(DLT_RAW);
-        }
-        aun->length = len;
-
         /* IDS mode reverse the data */
         /** \todo improve the order selection policy */
         if (!StreamTcpInlineMode()) {
@@ -458,74 +531,11 @@ int Unified2PacketTypeAlert (Unified2AlertThread *aun, Packet *p, uint32_t event
                 flag = FLOW_PKT_TOCLIENT;
             }
         }
-        if (aun->length > aun->datalen) {
-            SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data: %d vs %d",
-                    aun->length, aun->datalen);
-            return -1;
-        }
-        aun->offset += sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE;
-
-        /* Include Packet header */
-        if (PKT_IS_IPV4(p)) {
-            FakeIPv4Hdr fakehdr;
-            uint32_t hdr_length = sizeof(FakeIPv4Hdr);
-
-            if (p->datalink == DLT_EN10MB) {
-                /* Fake this */
-                ethh_offset = 14;
-                datalink = DLT_EN10MB;
-                phdr->linktype = htonl(datalink);
-                aun->length += ethh_offset;
-                if (aun->length > aun->datalen) {
-                    SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data: %d vs %d",
-                            len, aun->datalen - aun->offset);
-                    return -1;
-                }
-                ethhdr.eth_type = htons(ETHERNET_TYPE_IP);
-
-                memcpy(aun->data + aun->offset, &ethhdr, 14);
-                aun->offset += ethh_offset;
-            }
 
-            memset(&fakehdr, 0, hdr_length);
-            Unified2ForgeFakeIPv4Header(&fakehdr, p, hdr_length, 0);
-            memcpy(aun->data + aun->offset, &fakehdr, hdr_length);
-            aun->iphdr = (void *)(aun->data + aun->offset);
-            aun->offset += hdr_length;
-            aun->length += hdr_length;
-        } else { /* Implied IPv6 */
-            FakeIPv6Hdr fakehdr;
-            uint32_t hdr_length = sizeof(FakeIPv6Hdr);
-
-            if (p->datalink == DLT_EN10MB) {
-                /* Fake this */
-                ethh_offset = 14;
-                datalink = DLT_EN10MB;
-                phdr->linktype = htonl(datalink);
-                aun->length += ethh_offset;
-                if (aun->length > aun->datalen) {
-                    SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data: %d vs %d",
-                            len, aun->datalen - aun->offset);
-                    return -1;
-                }
-                ethhdr.eth_type = htons(ETHERNET_TYPE_IPV6);
-
-                memcpy(aun->data + aun->offset, &ethhdr, 14);
-                aun->offset += ethh_offset;
-            }
+        /* make event id available to callback */
+        aun->event_id = event_id;
 
-            memset(&fakehdr, 0, hdr_length);
-            Unified2ForgeFakeIPv6Header(&fakehdr, p, hdr_length, 1);
-            aun->length += hdr_length;
-            if (aun->length > aun->datalen) {
-                SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data: %d vs %d",
-                        aun->length, aun->datalen);
-                return -1;
-            }
-            memcpy(aun->data + aun->offset, &fakehdr, hdr_length);
-            aun->iphdr = (void *)(aun->data + aun->offset);
-            aun->offset += hdr_length;
-        }
+        /* run callback for all segments in the stream */
         ret = StreamSegmentForEach(p, flag, Unified2PrintStreamSegmentCallback, (void *)aun);
     }
 
@@ -533,6 +543,27 @@ int Unified2PacketTypeAlert (Unified2AlertThread *aun, Packet *p, uint32_t event
     if (ret == 0) {
         SCLogDebug("no stream, no state: falling back to payload logging");
 
+        Unified2AlertFileHeader *hdr = (Unified2AlertFileHeader*)(aun->data);
+        Unified2Packet *phdr = (Unified2Packet *)(hdr + 1);
+        int len = (sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE);
+        int datalink = p->datalink;
+#ifdef HAVE_OLD_BARNYARD2
+        int ethh_offset = 0;
+        EthernetHdr ethhdr = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, htons(ETHERNET_TYPE_IPV6) };
+#endif
+        memset(hdr, 0, sizeof(Unified2AlertFileHeader));
+        memset(phdr, 0, sizeof(Unified2Packet));
+
+        hdr->type = htonl(UNIFIED2_PACKET_TYPE);
+        aun->hdr = hdr;
+
+        phdr->sensor_id = 0;
+        phdr->linktype = htonl(datalink);
+        phdr->event_id =  event_id;
+        phdr->event_second = phdr->packet_second = htonl(p->ts.tv_sec);
+        phdr->packet_microsecond = htonl(p->ts.tv_usec);
+        aun->phdr = phdr;
+
         /* we need to reset offset and length which could
          * have been modified by the segment logging */
         aun->offset = len;