[Oisf-devel] [PATCH 1/2] Modify Packet structure and prepare accessor.

Eric Leblond eleblond at edenwall.com
Sat Nov 20 17:57:42 UTC 2010


This patch modifies decode.c and decode.h to avoid the usage
by default of a bigger than 65535 bytes array in Packet structure.
The idea is that the packet are mainly under 1514 bytes size and
a bigger size must be supported but should not be the default.

If the packet length is bigger than DFLT_PACKET_SIZE then the
data are stored in a dynamically allocated part of the memory.

To ease the modification of the rest of the code, functions to
access and set the payload/length in a Packet have been introduced.

The default packet size can be set at runtime via the default-packet-size
configuration variable.

Signed-off-by: Eric Leblond <eleblond at edenwall.com>
---
 src/decode.c          |   58 ++++++++++++++++++++++++++++++++++++++++++++++--
 src/decode.h          |   27 +++++++++++++++++++---
 src/suricata.c        |    6 +++++
 src/tmqh-packetpool.c |   11 +++++++++
 suricata.yaml         |    5 ++++
 5 files changed, 100 insertions(+), 7 deletions(-)

diff --git a/src/decode.c b/src/decode.c
index d9e02a2..f353549 100644
--- a/src/decode.c
+++ b/src/decode.c
@@ -27,6 +27,7 @@
 #include "suricata.h"
 #include "decode.h"
 #include "util-debug.h"
+#include "util-mem.h"
 #include "app-layer-detect-proto.h"
 #include "tm-modules.h"
 #include "util-error.h"
@@ -66,7 +67,7 @@ Packet *PacketGetFromQueueOrAlloc(void) {
 
     if (p == NULL) {
         /* non fatal, we're just not processing a packet then */
-        p = SCMalloc(sizeof(Packet));
+        p = SCMalloc(SIZE_OF_PACKET);
         if (p == NULL) {
             SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s", strerror(errno));
             return NULL;
@@ -107,8 +108,7 @@ Packet *PacketPseudoPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t
 
     /* copy packet and set lenght, proto */
     p->tunnel_proto = proto;
-    p->pktlen = len;
-    memcpy(&p->pkt, pkt, len);
+    PacketCopyData(p, pkt, len);
     p->recursion_level = parent->recursion_level + 1;
     p->ts.tv_sec = parent->ts.tv_sec;
     p->ts.tv_usec = parent->ts.tv_usec;
@@ -243,3 +243,55 @@ DecodeThreadVars *DecodeThreadVarsAlloc() {
 
     return dtv;
 }
+
+/**
+ *  \brief Copy data to Packet payload at given offset
+ *
+ *  \param Pointer to the Packet to modify
+ *  \param Offset of the copy relatively to payload of Packet
+ *  \param Pointer to the data to copy
+ *  \param Length of the data to copy
+ */
+inline int PacketCopyDataOffset(Packet *p, int offset, uint8_t *data, int datalen)
+{
+    if (offset + datalen > MAX_PAYLOAD_SIZE) {
+        /* too big */
+        return -1;
+    }
+
+    if (! p->ext_pkt) {
+        if (offset + datalen <= default_packet_size) {
+            memcpy(p->pkt + offset, data, datalen);
+        } else {
+            /* here we need a dynamic allocation. This case should rarely
+             * occur as there is a high probability the first frag has
+             * reveal the packet size*/
+            p->ext_pkt = SCMalloc(MAX_PAYLOAD_SIZE);
+            if (p->ext_pkt == NULL) {
+                SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s", strerror(errno));
+                SET_PKT_LEN(p, 0);
+                return -1;
+            }
+            /* copy initial data */
+            memcpy(p->ext_pkt, &p->pkt, p->pktlen);
+            /* copy data as asked */
+            memcpy(p->ext_pkt + offset, data, datalen);
+        }
+    } else {
+        memcpy(p->ext_pkt + offset, data, datalen);
+    }
+    return 0;
+}
+
+/**
+ *  \brief Copy data to Packet payload and set packet length
+ *
+ *  \param Pointer to the Packet to modify
+ *  \param Pointer to the data to copy
+ *  \param Length of the data to copy
+ */
+inline int PacketCopyData(Packet *p, uint8_t *pktdata, int pktlen)
+{
+    SET_PKT_LEN(p, (size_t)pktlen);
+    return PacketCopyDataOffset(p, 0, pktdata, pktlen);
+}
diff --git a/src/decode.h b/src/decode.h
index b911ed5..d86d11e 100644
--- a/src/decode.h
+++ b/src/decode.h
@@ -163,6 +163,14 @@ typedef struct Address_ {
 #define GET_TCP_SRC_PORT(p)  ((p)->sp)
 #define GET_TCP_DST_PORT(p)  ((p)->dp)
 
+#define GET_PKT_LEN(p) ((p)->pktlen)
+#define GET_PKT_DATA(p) ((((p)->ext_pkt) == NULL ) ? (p)->pkt : (p)->ext_pkt)
+
+#define SET_PKT_LEN(p, len) do { \
+    (p)->pktlen = len;		 \
+    } while (0)
+
+
 /* Port is just a uint16_t */
 typedef uint16_t Port;
 #define SET_PORT(v, p) ((p) = (v))
@@ -347,8 +355,9 @@ typedef struct Packet_
     uint8_t *payload;
     uint16_t payload_len;
 
-    /* storage: maximum ip packet size + link header */
-    uint8_t pkt[IPV6_HEADER_LEN + 65536 + 28];
+    /* storage: set to pointer to heap and extended via allocation if necessary */
+    uint8_t *pkt;
+    uint8_t *ext_pkt;
     uint32_t pktlen;
 
     PacketAlerts alerts;
@@ -402,6 +411,12 @@ typedef struct Packet_
 #endif
 } Packet;
 
+#define DEFAULT_PACKET_SIZE 1500 + ETHERNET_HEADER_LEN
+/* storage: maximum ip packet size + link header */
+#define MAX_PAYLOAD_SIZE IPV6_HEADER_LEN + 65536 + 28
+intmax_t default_packet_size;
+#define SIZE_OF_PACKET default_packet_size + sizeof(Packet)
+
 typedef struct PacketQueue_ {
     Packet *top;
     Packet *bot;
@@ -478,17 +493,19 @@ typedef struct DecodeThreadVars_
  */
 #ifndef __SC_CUDA_SUPPORT__
 #define PACKET_INITIALIZE(p) { \
-    memset((p), 0x00, sizeof(Packet)); \
+    memset((p), 0x00, SIZE_OF_PACKET); \
     SCMutexInit(&(p)->mutex_rtv_cnt, NULL); \
     PACKET_RESET_CHECKSUMS((p)); \
+    (p)->pkt = ((uint8_t *)(p)) + sizeof(Packet); \
 }
 #else
 #define PACKET_INITIALIZE(p) { \
-    memset((p), 0x00, sizeof(Packet)); \
+    memset((p), 0x00, SIZE_OF_PACKET); \
     SCMutexInit(&(p)->mutex_rtv_cnt, NULL); \
     PACKET_RESET_CHECKSUMS((p)); \
     SCMutexInit(&(p)->cuda_mutex, NULL); \
     SCCondInit(&(p)->cuda_cond, NULL); \
+    (p)->pkt = ((uint8_t *)(p)) + sizeof(Packet); \
 }
 #endif
 
@@ -634,6 +651,8 @@ typedef struct DecodeThreadVars_
 void DecodeRegisterPerfCounters(DecodeThreadVars *, ThreadVars *);
 Packet *PacketPseudoPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t proto);
 Packet *PacketGetFromQueueOrAlloc(void);
+int PacketCopyData(Packet *p, uint8_t *pktdata, int pktlen);
+int PacketCopyDataOffset(Packet *p, int offset, uint8_t *data, int datalen);
 
 DecodeThreadVars *DecodeThreadVarsAlloc();
 
diff --git a/src/suricata.c b/src/suricata.c
index 8661619..0b967ac 100644
--- a/src/suricata.c
+++ b/src/suricata.c
@@ -784,6 +784,12 @@ int main(int argc, char **argv)
         max_pending_packets = DEFAULT_MAX_PENDING_PACKETS;
     SCLogDebug("Max pending packets set to %"PRIiMAX, max_pending_packets);
 
+    /* Pull the default packet size from the config, if not found fall
+     * back on a sane default. */
+    if (ConfGetInt("default-packet-size", &default_packet_size) != 1)
+        default_packet_size = DEFAULT_PACKET_SIZE;
+    SCLogDebug("Default packet size set to %"PRIiMAX, default_packet_size);
+
     /* Since our config is now loaded we can finish configurating the
      * logging module. */
     SCLogLoadConfig();
diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c
index 1cc028b..adc9310 100644
--- a/src/tmqh-packetpool.c
+++ b/src/tmqh-packetpool.c
@@ -186,6 +186,11 @@ void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
     /* we're done with the tunnel root now as well */
     if (proot == 1) {
         SCLogDebug("getting rid of root pkt... alloc'd %s", p->root->flags & PKT_ALLOC ? "true" : "false");
+        /* if p->root uses extended data, free them */
+        if (p->root->ext_pkt) {
+            SCFree(p->root->ext_pkt);
+            p->root->ext_pkt = NULL;
+        }
         if (p->root->flags & PKT_ALLOC) {
             PACKET_CLEANUP(p->root);
             SCFree(p->root);
@@ -196,6 +201,12 @@ void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
         }
     }
 
+    /* if p uses extended data, free them */
+    if (p->ext_pkt) {
+        SCFree(p->ext_pkt);
+        p->ext_pkt = NULL;
+    }
+
     SCLogDebug("getting rid of tunnel pkt... alloc'd %s (root %p)", p->flags & PKT_ALLOC ? "true" : "false", p->root);
     if (p->flags & PKT_ALLOC) {
         PACKET_CLEANUP(p);
diff --git a/suricata.yaml b/suricata.yaml
index f805e55..7390b2e 100644
--- a/suricata.yaml
+++ b/suricata.yaml
@@ -10,6 +10,11 @@
 # pattern matcher scans many packets in parallel.
 #max-pending-packets: 50
 
+# Preallocated size for packet. Default is 1514 which is the classical
+# size for pcap on ethernet. You should adjust this value to the highest
+# packet size (MTU + hardware header) on your system.
+#default-packet-size: 1514
+
 # Set the order of alerts bassed on actions
 # The default order is pass, drop, reject, alert
 action-order:
-- 
1.7.2.3




More information about the Oisf-devel mailing list