CVE-2017-7177: Improperly Implemented Security Check for Standard (CWE-358)
value: Suricata before 3.2.1 has an IPv4 defragmentation evasion issue caused by lack of a check for the IP protocol during fragment matching.
CWE description: The product does not implement or incorrectly implements one or more security-relevant checks as specified by the design of a standardized algorithm, protocol, or technique.
CVSS v3 base score: 7.5
Published: 2017-03-18T20:59Z
Repository: https://github.com/inliniac/suricata
Language: C
Files changed: src/defrag-hash.c, src/defrag.c, src/defrag.h
Commit date: 2017-02-13 09:43:03 +0100
Commit message: defrag - take protocol into account during re-assembly

The IP protocol was not being used to match fragments with
their packets allowing a carefully constructed packet
with a different protocol to be matched, allowing re-assembly
to complete, creating a packet that would not be re-assembled
by the destination host.

Diff: diff --git a/src/defrag-hash.c b/src/defrag-hash.c
index 082eb496..736099c5 100644
--- a/src/defrag-hash.c
+++ b/src/defrag-hash.c
@@ -90,10 +90,11 @@ static void DefragTrackerInit(DefragTracker *dt, Packet *p)
         dt->af = AF_INET;
     } else {
         dt->id = (int32_t)IPV6_EXTHDR_GET_FH_ID(p);
         dt->af = AF_INET6;
     }
+    dt->proto = IP_GET_IPPROTO(p);
     dt->vlan_id[0] = p->vlan_id[0];
     dt->vlan_id[1] = p->vlan_id[1];
     dt->policy = DefragGetOsPolicy(p);
     dt->host_timeout = DefragPolicyGetHostTimeout(p);
     dt->remove = 0;
@@ -404,10 +405,11 @@ static inline uint32_t DefragHashGetKey(Packet *p)
 #define CMP_DEFRAGTRACKER(d1,d2,id) \
     (((CMP_ADDR(&(d1)->src_addr, &(d2)->src) && \
        CMP_ADDR(&(d1)->dst_addr, &(d2)->dst)) || \
       (CMP_ADDR(&(d1)->src_addr, &(d2)->dst) && \
        CMP_ADDR(&(d1)->dst_addr, &(d2)->src))) && \
+     (d1)->proto == IP_GET_IPPROTO(p) &&        \
      (d1)->id == (id) && \
      (d1)->vlan_id[0] == (d2)->vlan_id[0] && \
      (d1)->vlan_id[1] == (d2)->vlan_id[1])
 
 static inline int DefragTrackerCompare(DefragTracker *t, Packet *p)
diff --git a/src/defrag.c b/src/defrag.c
index c7ebd9f9..5433ce78 100644
--- a/src/defrag.c
+++ b/src/defrag.c
@@ -994,12 +994,12 @@ void DefragDestroy(void)
 /**
  * Allocate a test packet.  Nothing to fancy, just a simple IP packet
  * with some payload of no particular protocol.
  */
 static Packet *
-BuildTestPacket(uint16_t id, uint16_t off, int mf, const char content,
-    int content_len)
+BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf,
+    const char content, int content_len)
 {
     Packet *p = NULL;
     int hlen = 20;
     int ttl = 64;
     uint8_t *pcontent;
@@ -1021,11 +1021,11 @@ BuildTestPacket(uint16_t id, uint16_t off, int mf, const char content,
     if (mf)
         ip4h.ip_off = htons(IP_MF | off);
     else
         ip4h.ip_off = htons(off);
     ip4h.ip_ttl = ttl;
-    ip4h.ip_proto = IPPROTO_ICMP;
+    ip4h.ip_proto = proto;
 
     ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
     ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
 
     /* copy content_len crap, we need full length */
@@ -1057,11 +1057,11 @@ BuildTestPacket(uint16_t id, uint16_t off, int mf, const char content,
         goto error;
     if (IPV4_GET_MF(p) != mf)
         goto error;
     if (IPV4_GET_IPTTL(p) != ttl)
         goto error;
-    if (IPV4_GET_IPPROTO(p) != IPPROTO_ICMP)
+    if (IPV4_GET_IPPROTO(p) != proto)
         goto error;
 
     return p;
 error:
     if (p != NULL)
@@ -1072,12 +1072,12 @@ error:
 void DecodeIPV6FragHeader(Packet *p, uint8_t *pkt,
                           uint16_t hdrextlen, uint16_t plen,
                           uint16_t prev_hdrextlen);
 
 static Packet *
-IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content,
-    int content_len)
+IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off, int mf,
+    const char content, int content_len)
 {
     Packet *p = NULL;
     uint8_t *pcontent;
     IPV6Hdr ip6h;
 
@@ -1107,11 +1107,11 @@ IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content,
 
     p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p);
     IPV6_SET_RAW_VER(p->ip6h, 6);
     /* Fragmentation header. */
     IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
-    fh->ip6fh_nxt = IPPROTO_ICMP;
+    fh->ip6fh_nxt = proto;
     fh->ip6fh_ident = htonl(id);
     fh->ip6fh_offlg = htons((off << 3) | mf);
 
     DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
 
@@ -1157,17 +1157,17 @@ DefragInOrderSimpleTest(void)
     int i;
     int ret = 0;
 
     DefragInit();
 
-    p1 = BuildTestPacket(id, 0, 1, 'A', 8);
+    p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
     if (p1 == NULL)
         goto end;
-    p2 = BuildTestPacket(id, 1, 1, 'B', 8);
+    p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
     if (p2 == NULL)
         goto end;
-    p3 = BuildTestPacket(id, 2, 0, 'C', 3);
+    p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
     if (p3 == NULL)
         goto end;
 
     if (Defrag(NULL, NULL, p1, NULL) != NULL)
         goto end;
@@ -1234,17 +1234,17 @@ DefragReverseSimpleTest(void)
     int i;
     int ret = 0;
 
     DefragInit();
 
-    p1 = BuildTestPacket(id, 0, 1, 'A', 8);
+    p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
     if (p1 == NULL)
         goto end;
-    p2 = BuildTestPacket(id, 1, 1, 'B', 8);
+    p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
     if (p2 == NULL)
         goto end;
-    p3 = BuildTestPacket(id, 2, 0, 'C', 3);
+    p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
     if (p3 == NULL)
         goto end;
 
     if (Defrag(NULL, NULL, p3, NULL) != NULL)
         goto end;
@@ -1306,17 +1306,17 @@ IPV6DefragInOrderSimpleTest(void)
     int i;
     int ret = 0;
 
     DefragInit();
 
-    p1 = IPV6BuildTestPacket(id, 0, 1, 'A', 8);
+    p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
     if (p1 == NULL)
         goto end;
-    p2 = IPV6BuildTestPacket(id, 1, 1, 'B', 8);
+    p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
     if (p2 == NULL)
         goto end;
-    p3 = IPV6BuildTestPacket(id, 2, 0, 'C', 3);
+    p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
     if (p3 == NULL)
         goto end;
 
     if (Defrag(NULL, NULL, p1, NULL) != NULL)
         goto end;
@@ -1376,17 +1376,17 @@ IPV6DefragReverseSimpleTest(void)
 
     dc = DefragContextNew();
     if (dc == NULL)
         goto end;
 
-    p1 = IPV6BuildTestPacket(id, 0, 1, 'A', 8);
+    p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
     if (p1 == NULL)
         goto end;
-    p2 = IPV6BuildTestPacket(id, 1, 1, 'B', 8);
+    p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
     if (p2 == NULL)
         goto end;
-    p3 = IPV6BuildTestPacket(id, 2, 0, 'C', 3);
+    p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
     if (p3 == NULL)
         goto end;
 
     if (Defrag(NULL, NULL, p3, NULL) != NULL)
         goto end;
@@ -1450,63 +1450,63 @@ DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len)
     /*
      * Original fragments.
      */
 
     /* A*24 at 0. */
-    packets[0] = BuildTestPacket(id, 0, 1, 'A', 24);
+    packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
 
     /* B*15 at 32. */
-    packets[1] = BuildTestPacket(id, 32 >> 3, 1, 'B', 16);
+    packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
 
     /* C*24 at 48. */
-    packets[2] = BuildTestPacket(id, 48 >> 3, 1, 'C', 24);
+    packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
 
     /* D*8 at 80. */
-    packets[3] = BuildTestPacket(id, 80 >> 3, 1, 'D', 8);
+    packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
 
     /* E*16 at 104. */
-    packets[4] = BuildTestPacket(id, 104 >> 3, 1, 'E', 16);
+    packets[4] = BuildTestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
 
     /* F*24 at 120. */
-    packets[5] = BuildTestPacket(id, 120 >> 3, 1, 'F', 24);
+    packets[5] = BuildTestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
 
     /* G*16 at 144. */
-    packets[6] = BuildTestPacket(id, 144 >> 3, 1, 'G', 16);
+    packets[6] = BuildTestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
 
     /* H*16 at 160. */
-    packets[7] = BuildTestPacket(id, 160 >> 3, 1, 'H', 16);
+    packets[7] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
 
     /* I*8 at 176. */
-    packets[8] = BuildTestPacket(id, 176 >> 3, 1, 'I', 8);
+    packets[8] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
 
     /*
      * Overlapping subsequent fragments.
      */
 
     /* J*32 at 8. */
-    packets[9] = BuildTestPacket(id, 8 >> 3, 1, 'J', 32);
+    packets[9] = BuildTestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
 
     /* K*24 at 48. */
-    packets[10] = BuildTestPacket(id, 48 >> 3, 1, 'K', 24);
+    packets[10] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
 
     /* L*24 at 72. */
-    packets[11] = BuildTestPacket(id, 72 >> 3, 1, 'L', 24);
+    packets[11] = BuildTestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
 
     /* M*24 at 96. */
-    packets[12] = BuildTestPacket(id, 96 >> 3, 1, 'M', 24);
+    packets[12] = BuildTestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
 
     /* N*8 at 128. */
-    packets[13] = BuildTestPacket(id, 128 >> 3, 1, 'N', 8);
+    packets[13] = BuildTestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
 
     /* O*8 at 152. */
-    packets[14] = BuildTestPacket(id, 152 >> 3, 1, 'O', 8);
+    packets[14] = BuildTestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
 
     /* P*8 at 160. */
-    packets[15] = BuildTestPacket(id, 160 >> 3, 1, 'P', 8);
+    packets[15] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
 
     /* Q*16 at 176. */
-    packets[16] = BuildTestPacket(id, 176 >> 3, 0, 'Q', 16);
+    packets[16] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
 
     default_policy = policy;
 
     /* Send all but the last. */
     for (i = 0; i < 9; i++) {
@@ -1585,63 +1585,63 @@ IPV6DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len)
     /*
      * Original fragments.
      */
 
     /* A*24 at 0. */
-    packets[0] = IPV6BuildTestPacket(id, 0, 1, 'A', 24);
+    packets[0] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
 
     /* B*15 at 32. */
-    packets[1] = IPV6BuildTestPacket(id, 32 >> 3, 1, 'B', 16);
+    packets[1] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
 
     /* C*24 at 48. */
-    packets[2] = IPV6BuildTestPacket(id, 48 >> 3, 1, 'C', 24);
+    packets[2] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
 
     /* D*8 at 80. */
-    packets[3] = IPV6BuildTestPacket(id, 80 >> 3, 1, 'D', 8);
+    packets[3] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
 
     /* E*16 at 104. */
-    packets[4] = IPV6BuildTestPacket(id, 104 >> 3, 1, 'E', 16);
+    packets[4] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
 
     /* F*24 at 120. */
-    packets[5] = IPV6BuildTestPacket(id, 120 >> 3, 1, 'F', 24);
+    packets[5] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
 
     /* G*16 at 144. */
-    packets[6] = IPV6BuildTestPacket(id, 144 >> 3, 1, 'G', 16);
+    packets[6] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
 
     /* H*16 at 160. */
-    packets[7] = IPV6BuildTestPacket(id, 160 >> 3, 1, 'H', 16);
+    packets[7] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
 
     /* I*8 at 176. */
-    packets[8] = IPV6BuildTestPacket(id, 176 >> 3, 1, 'I', 8);
+    packets[8] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
 
     /*
      * Overlapping subsequent fragments.
      */
 
     /* J*32 at 8. */
-    packets[9] = IPV6BuildTestPacket(id, 8 >> 3, 1, 'J', 32);
+    packets[9] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
 
     /* K*24 at 48. */
-    packets[10] = IPV6BuildTestPacket(id, 48 >> 3, 1, 'K', 24);
+    packets[10] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
 
     /* L*24 at 72. */
-    packets[11] = IPV6BuildTestPacket(id, 72 >> 3, 1, 'L', 24);
+    packets[11] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
 
     /* M*24 at 96. */
-    packets[12] = IPV6BuildTestPacket(id, 96 >> 3, 1, 'M', 24);
+    packets[12] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
 
     /* N*8 at 128. */
-    packets[13] = IPV6BuildTestPacket(id, 128 >> 3, 1, 'N', 8);
+    packets[13] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
 
     /* O*8 at 152. */
-    packets[14] = IPV6BuildTestPacket(id, 152 >> 3, 1, 'O', 8);
+    packets[14] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
 
     /* P*8 at 160. */
-    packets[15] = IPV6BuildTestPacket(id, 160 >> 3, 1, 'P', 8);
+    packets[15] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
 
     /* Q*16 at 176. */
-    packets[16] = IPV6BuildTestPacket(id, 176 >> 3, 0, 'Q', 16);
+    packets[16] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
 
     default_policy = policy;
 
     /* Send all but the last. */
     for (i = 0; i < 9; i++) {
@@ -2123,11 +2123,11 @@ DefragTimeoutTest(void)
 
     DefragInit();
 
     /* Load in 16 packets. */
     for (i = 0; i < 16; i++) {
-        Packet *p = BuildTestPacket(i, 0, 1, 'A' + i, 16);
+        Packet *p = BuildTestPacket(IPPROTO_ICMP,i, 0, 1, 'A' + i, 16);
         if (p == NULL)
             goto end;
 
         Packet *tp = Defrag(NULL, NULL, p, NULL);
 
@@ -2139,11 +2139,11 @@ DefragTimeoutTest(void)
         }
     }
 
     /* Build a new packet but push the timestamp out by our timeout.
      * This should force our previous fragments to be timed out. */
-    Packet *p = BuildTestPacket(99, 0, 1, 'A' + i, 16);
+    Packet *p = BuildTestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
     if (p == NULL)
         goto end;
 
     p->ts.tv_sec += (defrag_context->timeout + 1);
     Packet *tp = Defrag(NULL, NULL, p, NULL);
@@ -2187,11 +2187,11 @@ DefragIPv4NoDataTest(void)
     dc = DefragContextNew();
     if (dc == NULL)
         goto end;
 
     /* This packet has an offset > 0, more frags set to 0 and no data. */
-    p = BuildTestPacket(id, 1, 0, 'A', 0);
+    p = BuildTestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
     if (p == NULL)
         goto end;
 
     /* We do not expect a packet returned. */
     if (Defrag(NULL, NULL, p, NULL) != NULL)
@@ -2226,11 +2226,11 @@ DefragIPv4TooLargeTest(void)
     if (dc == NULL)
         goto end;
 
     /* Create a fragment that would extend past the max allowable size
      * for an IPv4 packet. */
-    p = BuildTestPacket(1, 8183, 0, 'A', 71);
+    p = BuildTestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
     if (p == NULL)
         goto end;
 
     /* We do not expect a packet returned. */
     if (Defrag(NULL, NULL, p, NULL) != NULL)
@@ -2265,14 +2265,14 @@ DefragVlanTest(void)
     Packet *p1 = NULL, *p2 = NULL, *r = NULL;
     int ret = 0;
 
     DefragInit();
 
-    p1 = BuildTestPacket(1, 0, 1, 'A', 8);
+    p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
     if (p1 == NULL)
         goto end;
-    p2 = BuildTestPacket(1, 1, 0, 'B', 8);
+    p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
     if (p2 == NULL)
         goto end;
 
     /* With no VLAN IDs set, packets should re-assemble. */
     if ((r = Defrag(NULL, NULL, p1, NULL)) != NULL)
@@ -2311,14 +2311,14 @@ DefragVlanQinQTest(void)
     Packet *p1 = NULL, *p2 = NULL, *r = NULL;
     int ret = 0;
 
     DefragInit();
 
-    p1 = BuildTestPacket(1, 0, 1, 'A', 8);
+    p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
     if (p1 == NULL)
         goto end;
-    p2 = BuildTestPacket(1, 1, 0, 'B', 8);
+    p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
     if (p2 == NULL)
         goto end;
 
     /* With no VLAN IDs set, packets should re-assemble. */
     if ((r = Defrag(NULL, NULL, p1, NULL)) != NULL)
@@ -2359,11 +2359,11 @@ static int DefragTrackerReuseTest(void)
 
     DefragInit();
 
     /* Build a packet, its not a fragment but shouldn't matter for
      * this test. */
-    p1 = BuildTestPacket(id, 0, 0, 'A', 8);
+    p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
     if (p1 == NULL) {
         goto end;
     }
 
     /* Get a tracker. It shouldn't look like its already in use. */
@@ -2429,13 +2429,13 @@ static int DefragMfIpv4Test(void)
     int ip_id = 9;
     Packet *p = NULL;
 
     DefragInit();
 
-    Packet *p1 = BuildTestPacket(ip_id, 2, 1, 'C', 8);
-    Packet *p2 = BuildTestPacket(ip_id, 0, 1, 'A', 8);
-    Packet *p3 = BuildTestPacket(ip_id, 1, 0, 'B', 8);
+    Packet *p1 = BuildTestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
+    Packet *p2 = BuildTestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
+    Packet *p3 = BuildTestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
     if (p1 == NULL || p2 == NULL || p3 == NULL) {
         goto end;
     }
 
     p = Defrag(NULL, NULL, p1, NULL);
@@ -2493,13 +2493,13 @@ static int DefragMfIpv6Test(void)
     int ip_id = 9;
     Packet *p = NULL;
 
     DefragInit();
 
-    Packet *p1 = IPV6BuildTestPacket(ip_id, 2, 1, 'C', 8);
-    Packet *p2 = IPV6BuildTestPacket(ip_id, 0, 1, 'A', 8);
-    Packet *p3 = IPV6BuildTestPacket(ip_id, 1, 0, 'B', 8);
+    Packet *p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
+    Packet *p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
+    Packet *p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
     if (p1 == NULL || p2 == NULL || p3 == NULL) {
         goto end;
     }
 
     p = Defrag(NULL, NULL, p1, NULL);
@@ -2540,10 +2540,43 @@ end:
     }
     DefragDestroy();
     return retval;
 }
 
+/**
+ * \brief Test that fragments that match other than the proto don't
+ * actually get matched.
+ */
+static int DefragTestBadProto(void)
+{
+    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
+    int id = 12;
+
+    DefragInit();
+
+    p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
+    FAIL_IF_NULL(p1);
+    p2 = BuildTestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
+    FAIL_IF_NULL(p2);
+    p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
+    FAIL_IF_NULL(p3);
+
+    FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p1, NULL));
+    FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p2, NULL));
+    FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p3, NULL));
+
+    if (p1 != NULL)
+        SCFree(p1);
+    if (p2 != NULL)
+        SCFree(p2);
+    if (p3 != NULL)
+        SCFree(p3);
+
+    DefragDestroy();
+    PASS;
+}
+
 #endif /* UNITTESTS */
 
 void
 DefragRegisterTests(void)
 {
@@ -2581,8 +2614,9 @@ DefragRegisterTests(void)
     UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest);
     UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest);
     UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest);
     UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test);
     UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test);
+    UtRegisterTest("DefragTestBadProto", DefragTestBadProto);
 #endif /* UNITTESTS */
 }
 
diff --git a/src/defrag.h b/src/defrag.h
index 2dfaec60..c3a0c693 100644
--- a/src/defrag.h
+++ b/src/defrag.h
@@ -82,10 +82,12 @@ typedef struct DefragTracker_ {
     uint16_t vlan_id[2]; /**< VLAN ID tracker applies to. */
 
     uint32_t id; /**< IP ID for this tracker.  32 bits for IPv6, 16
                   * for IPv4. */
 
+    uint8_t proto; /**< IP protocol for this tracker. */
+
     uint8_t policy; /**< Reassembly policy this tracker will use. */
 
     uint8_t af; /**< Address family for this tracker, AF_INET or
                  * AF_INET6. */
 

Vulnerable code: BuildTestPacket(uint16_t id, uint16_t off, int mf, const char content,
    int content_len)
    ip4h.ip_proto = IPPROTO_ICMP;
    if (IPV4_GET_IPPROTO(p) != IPPROTO_ICMP)
IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content,
    int content_len)
    fh->ip6fh_nxt = IPPROTO_ICMP;
    p1 = BuildTestPacket(id, 0, 1, 'A', 8);
    p2 = BuildTestPacket(id, 1, 1, 'B', 8);
    p3 = BuildTestPacket(id, 2, 0, 'C', 3);
    p1 = BuildTestPacket(id, 0, 1, 'A', 8);
    p2 = BuildTestPacket(id, 1, 1, 'B', 8);
    p3 = BuildTestPacket(id, 2, 0, 'C', 3);
    p1 = IPV6BuildTestPacket(id, 0, 1, 'A', 8);
    p2 = IPV6BuildTestPacket(id, 1, 1, 'B', 8);
    p3 = IPV6BuildTestPacket(id, 2, 0, 'C', 3);
    p1 = IPV6BuildTestPacket(id, 0, 1, 'A', 8);
    p2 = IPV6BuildTestPacket(id, 1, 1, 'B', 8);
    p3 = IPV6BuildTestPacket(id, 2, 0, 'C', 3);
    packets[0] = BuildTestPacket(id, 0, 1, 'A', 24);
    packets[1] = BuildTestPacket(id, 32 >> 3, 1, 'B', 16);
    packets[2] = BuildTestPacket(id, 48 >> 3, 1, 'C', 24);
    packets[3] = BuildTestPacket(id, 80 >> 3, 1, 'D', 8);
    packets[4] = BuildTestPacket(id, 104 >> 3, 1, 'E', 16);
    packets[5] = BuildTestPacket(id, 120 >> 3, 1, 'F', 24);
    packets[6] = BuildTestPacket(id, 144 >> 3, 1, 'G', 16);
    packets[7] = BuildTestPacket(id, 160 >> 3, 1, 'H', 16);
    packets[8] = BuildTestPacket(id, 176 >> 3, 1, 'I', 8);
    packets[9] = BuildTestPacket(id, 8 >> 3, 1, 'J', 32);
    packets[10] = BuildTestPacket(id, 48 >> 3, 1, 'K', 24);
    packets[11] = BuildTestPacket(id, 72 >> 3, 1, 'L', 24);
    packets[12] = BuildTestPacket(id, 96 >> 3, 1, 'M', 24);
    packets[13] = BuildTestPacket(id, 128 >> 3, 1, 'N', 8);
    packets[14] = BuildTestPacket(id, 152 >> 3, 1, 'O', 8);
    packets[15] = BuildTestPacket(id, 160 >> 3, 1, 'P', 8);
    packets[16] = BuildTestPacket(id, 176 >> 3, 0, 'Q', 16);
    packets[0] = IPV6BuildTestPacket(id, 0, 1, 'A', 24);
    packets[1] = IPV6BuildTestPacket(id, 32 >> 3, 1, 'B', 16);
    packets[2] = IPV6BuildTestPacket(id, 48 >> 3, 1, 'C', 24);
    packets[3] = IPV6BuildTestPacket(id, 80 >> 3, 1, 'D', 8);
    packets[4] = IPV6BuildTestPacket(id, 104 >> 3, 1, 'E', 16);
    packets[5] = IPV6BuildTestPacket(id, 120 >> 3, 1, 'F', 24);
    packets[6] = IPV6BuildTestPacket(id, 144 >> 3, 1, 'G', 16);
    packets[7] = IPV6BuildTestPacket(id, 160 >> 3, 1, 'H', 16);
    packets[8] = IPV6BuildTestPacket(id, 176 >> 3, 1, 'I', 8);
    packets[9] = IPV6BuildTestPacket(id, 8 >> 3, 1, 'J', 32);
    packets[10] = IPV6BuildTestPacket(id, 48 >> 3, 1, 'K', 24);
    packets[11] = IPV6BuildTestPacket(id, 72 >> 3, 1, 'L', 24);
    packets[12] = IPV6BuildTestPacket(id, 96 >> 3, 1, 'M', 24);
    packets[13] = IPV6BuildTestPacket(id, 128 >> 3, 1, 'N', 8);
    packets[14] = IPV6BuildTestPacket(id, 152 >> 3, 1, 'O', 8);
    packets[15] = IPV6BuildTestPacket(id, 160 >> 3, 1, 'P', 8);
    packets[16] = IPV6BuildTestPacket(id, 176 >> 3, 0, 'Q', 16);
        Packet *p = BuildTestPacket(i, 0, 1, 'A' + i, 16);
    Packet *p = BuildTestPacket(99, 0, 1, 'A' + i, 16);
    p = BuildTestPacket(id, 1, 0, 'A', 0);
    p = BuildTestPacket(1, 8183, 0, 'A', 71);
    p1 = BuildTestPacket(1, 0, 1, 'A', 8);
    p2 = BuildTestPacket(1, 1, 0, 'B', 8);
    p1 = BuildTestPacket(1, 0, 1, 'A', 8);
    p2 = BuildTestPacket(1, 1, 0, 'B', 8);
    p1 = BuildTestPacket(id, 0, 0, 'A', 8);
    Packet *p1 = BuildTestPacket(ip_id, 2, 1, 'C', 8);
    Packet *p2 = BuildTestPacket(ip_id, 0, 1, 'A', 8);
    Packet *p3 = BuildTestPacket(ip_id, 1, 0, 'B', 8);
    Packet *p1 = IPV6BuildTestPacket(ip_id, 2, 1, 'C', 8);
    Packet *p2 = IPV6BuildTestPacket(ip_id, 0, 1, 'A', 8);
    Packet *p3 = IPV6BuildTestPacket(ip_id, 1, 0, 'B', 8);
Fixed code:     dt->proto = IP_GET_IPPROTO(p);
     (d1)->proto == IP_GET_IPPROTO(p) &&        \
BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf,
    const char content, int content_len)
    ip4h.ip_proto = proto;
    if (IPV4_GET_IPPROTO(p) != proto)
IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off, int mf,
    const char content, int content_len)
    fh->ip6fh_nxt = proto;
    p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
    p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
    p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
    p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
    p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
    p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
    p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
    p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
    p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
    p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
    p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
    p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
    packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
    packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
    packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
    packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
    packets[4] = BuildTestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
    packets[5] = BuildTestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
    packets[6] = BuildTestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
    packets[7] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
    packets[8] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
    packets[9] = BuildTestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
    packets[10] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
    packets[11] = BuildTestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
    packets[12] = BuildTestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
    packets[13] = BuildTestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
    packets[14] = BuildTestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
    packets[15] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
    packets[16] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
    packets[0] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
    packets[1] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
    packets[2] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
    packets[3] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
    packets[4] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
    packets[5] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
    packets[6] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
    packets[7] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
    packets[8] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
    packets[9] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
    packets[10] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
    packets[11] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
    packets[12] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
    packets[13] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
    packets[14] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
    packets[15] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
    packets[16] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
        Packet *p = BuildTestPacket(IPPROTO_ICMP,i, 0, 1, 'A' + i, 16);
    Packet *p = BuildTestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
    p = BuildTestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
    p = BuildTestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
    p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
    p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
    p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
    p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
    p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
    Packet *p1 = BuildTestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
    Packet *p2 = BuildTestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
    Packet *p3 = BuildTestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
    Packet *p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
    Packet *p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
    Packet *p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
/**
 * \brief Test that fragments that match other than the proto don't
 * actually get matched.
 */
static int DefragTestBadProto(void)
{
    Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
    int id = 12;

    DefragInit();

    p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
    FAIL_IF_NULL(p1);
    p2 = BuildTestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
    FAIL_IF_NULL(p2);
    p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
    FAIL_IF_NULL(p3);

    FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p1, NULL));
    FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p2, NULL));
    FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p3, NULL));

    if (p1 != NULL)
        SCFree(p1);
    if (p2 != NULL)
        SCFree(p2);
    if (p3 != NULL)
        SCFree(p3);

    DefragDestroy();
    PASS;
}

    UtRegisterTest("DefragTestBadProto", DefragTestBadProto);
    uint8_t proto; /**< IP protocol for this tracker. */