Tests various forms of RST triggering handling of unACK'd data.
--- /dev/null
+Test
+====
+
+Test series that tests if a RST that comes in before all data is ACK'd the
+unACK'd data is still reassembled and inspected, but does not trigger a GAP
+event.
+
+This test tests raw reassembly inspection of unack'd data w/o GAP.
--- /dev/null
+alert tcp any any -> any any (content:"Let Me In"; sid:1;)
+alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; threshold:type backoff, track by_flow, count 1, multiplier 10; classtype:protocol-command-decode; sid:2210048; rev:3;)
--- /dev/null
+requires:
+ min-version: 8
+
+checks:
+ - filter:
+ count: 1
+ match:
+ event_type: alert
+ alert.signature_id: 1
+ pkt_src: "stream (flow timeout)"
+ - filter:
+ count: 0
+ match:
+ event_type: alert
+ alert.signature_id: 2210048
+ - filter:
+ count: 1
+ match:
+ event_type: stats
+ stats.tcp.reassembly_gap: 0
--- /dev/null
+#!/usr/bin/env python
+from scapy.all import *
+
+pkts = []
+
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='S',seq=1,options=[('WScale', 14)])
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='SA',seq=1000,ack=2,options=[('WScale', 14)],window=65535)
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535)
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1001,ack=2,window=65535)/"Please "
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1008,ack=2,window=65535)/"Let "
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1012,ack=2,window=65535)/"Me "
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1015,ack=2,window=65535)/"In!"
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='RA',seq=2,ack=1008,window=65535)/"Access Denied"
+
+wrpcap('input.pcap', pkts)
--- /dev/null
+Test
+====
+
+Test series that tests if a RST that comes in before all data is ACK'd the
+unACK'd data is still reassembled and inspected, but does not trigger a GAP
+event.
+
+This test tests raw reassembly inspection of unack'd data w/o GAP in IPS mode.
--- /dev/null
+alert tcp any any -> any any (content:"Let Me In"; sid:1;)
+alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; threshold:type backoff, track by_flow, count 1, multiplier 10; classtype:protocol-command-decode; sid:2210048; rev:3;)
--- /dev/null
+requires:
+ min-version: 8
+
+checks:
+ - filter:
+ count: 1
+ match:
+ event_type: alert
+ alert.signature_id: 1
+ pcap_cnt: 7
+ - filter:
+ count: 0
+ match:
+ event_type: alert
+ alert.signature_id: 2210048
+ - filter:
+ count: 1
+ match:
+ event_type: stats
+ stats.tcp.reassembly_gap: 0
--- /dev/null
+#!/usr/bin/env python
+from scapy.all import *
+
+pkts = []
+
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='S',seq=1,options=[('WScale', 14)])
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='SA',seq=1000,ack=2,options=[('WScale', 14)],window=65535)
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535)
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1001,ack=2,window=65535)/"Please "
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1008,ack=2,window=65535)/"Let "
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1012,ack=2,window=65535)/"Me "
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1015,ack=2,window=65535)/"In!"
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='RA',seq=2,ack=1008,window=65535)/"Access Denied"
+
+wrpcap('input.pcap', pkts)
--- /dev/null
+Test
+====
+
+Test series that tests if a RST that comes in before all data is ACK'd the
+unACK'd data is still reassembled and inspected, but does not trigger a GAP
+event.
+
+This test tests raw reassembly inspection of unack'd data with GAP.
--- /dev/null
+alert tcp any any -> any any (content:"Me In"; sid:1;)
+alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; threshold:type backoff, track by_flow, count 1, multiplier 10; classtype:protocol-command-decode; sid:2210048; rev:3;)
--- /dev/null
+requires:
+ min-version: 8
+
+checks:
+ - filter:
+ count: 1
+ match:
+ event_type: alert
+ alert.signature_id: 1
+ pkt_src: "stream (flow timeout)"
+ - filter:
+ count: 0
+ match:
+ event_type: alert
+ alert.signature_id: 2210048
+ - filter:
+ count: 1
+ match:
+ event_type: stats
+ stats.tcp.reassembly_gap: 0
--- /dev/null
+#!/usr/bin/env python
+from scapy.all import *
+
+pkts = []
+
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='S',seq=1,options=[('WScale', 14)])
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='SA',seq=1000,ack=2,options=[('WScale', 14)],window=65535)
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535)
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1001,ack=2,window=65535)/"Please "
+#pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1008,ack=2,window=65535)/"Let "
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1012,ack=2,window=65535)/"Me "
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1015,ack=2,window=65535)/"In!"
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='RA',seq=2,ack=1008,window=65535)/"Access Denied"
+
+wrpcap('input.pcap', pkts)
--- /dev/null
+Test
+====
+
+Test series that tests if a RST that comes in before all data is ACK'd the
+unACK'd data is still reassembled and inspected, but does not trigger a GAP
+event.
+
+This test tests raw reassembly inspection of unack'd data with GAP in IPS mode.
--- /dev/null
+alert tcp any any -> any any (content:"Me In"; sid:1;)
+alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; threshold:type backoff, track by_flow, count 1, multiplier 10; classtype:protocol-command-decode; sid:2210048; rev:3;)
--- /dev/null
+requires:
+ min-version: 8
+
+checks:
+ - filter:
+ count: 1
+ match:
+ event_type: alert
+ alert.signature_id: 1
+ pcap_cnt: 6
+ - filter:
+ count: 0
+ match:
+ event_type: alert
+ alert.signature_id: 2210048
+ - filter:
+ count: 1
+ match:
+ event_type: stats
+ stats.tcp.reassembly_gap: 0
--- /dev/null
+#!/usr/bin/env python
+from scapy.all import *
+
+pkts = []
+
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='S',seq=1,options=[('WScale', 14)])
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='SA',seq=1000,ack=2,options=[('WScale', 14)],window=65535)
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535)
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1001,ack=2,window=65535)/"Please "
+#pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1008,ack=2,window=65535)/"Let "
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1012,ack=2,window=65535)/"Me "
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='AP',seq=1015,ack=2,window=65535)/"In!"
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='RA',seq=2,ack=1001,window=65535)/"Access Denied"
+
+wrpcap('input.pcap', pkts)
--- /dev/null
+Test
+====
+
+Test series that tests if a RST that comes in before all data is ACK'd the
+unACK'd data is still reassembled and inspected, but does not trigger a GAP
+event.
+
+This test tests HTTP reassembly inspection of unack'd data w/o GAP.
--- /dev/null
+alert tcp any any -> any any (content:"User-Agent: Mozilla"; sid:1;)
+alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; threshold:type backoff, track by_flow, count 1, multiplier 10; classtype:protocol-command-decode; sid:2210048; rev:3;)
--- /dev/null
+requires:
+ min-version: 8
+
+checks:
+ - filter:
+ count: 1
+ match:
+ event_type: alert
+ alert.signature_id: 1
+ pkt_src: "stream (flow timeout)"
+ - filter:
+ count: 0
+ match:
+ event_type: alert
+ alert.signature_id: 2210048
+ - filter:
+ count: 1
+ match:
+ event_type: stats
+ stats.tcp.reassembly_gap: 0
--- /dev/null
+#!/usr/bin/env python
+from scapy.all import *
+
+pkts = []
+
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='S',seq=1,options=[('WScale', 14)])
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='SA',seq=1000,ack=2,options=[('WScale', 14)],window=65535)
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535)
+
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535)/"GET / HTTP/1.0\r\n"
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=18,ack=1001,window=65535)/"Cookie: abcdef\r\n"
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=34,ack=1001,window=65535)/"User-Agent: "
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=46,ack=1001,window=65535)/"Mozilla\r\n\r\n"
+
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='RA',seq=1001,ack=18,window=65535)
+
+wrpcap('input.pcap', pkts)
--- /dev/null
+Test
+====
+
+Test series that tests if a RST that comes in before all data is ACK'd the
+unACK'd data is still reassembled and inspected, but does not trigger a GAP
+event.
+
+This test tests HTTP reassembly inspection of unack'd data w/o GAP in IPS mode.
--- /dev/null
+alert tcp any any -> any any (content:"User-Agent: Mozilla"; sid:1;)
+alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; threshold:type backoff, track by_flow, count 1, multiplier 10; classtype:protocol-command-decode; sid:2210048; rev:3;)
--- /dev/null
+requires:
+ min-version: 8
+
+checks:
+ - filter:
+ count: 1
+ match:
+ event_type: alert
+ alert.signature_id: 1
+ pcap_cnt: 7
+ - filter:
+ count: 0
+ match:
+ event_type: alert
+ alert.signature_id: 2210048
+ - filter:
+ count: 1
+ match:
+ event_type: stats
+ stats.tcp.reassembly_gap: 0
--- /dev/null
+#!/usr/bin/env python
+from scapy.all import *
+
+pkts = []
+
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='S',seq=1,options=[('WScale', 14)])
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='SA',seq=1000,ack=2,options=[('WScale', 14)],window=65535)
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535)
+
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535)/"GET / HTTP/1.0\r\n"
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=18,ack=1001,window=65535)/"Cookie: abcdef\r\n"
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=34,ack=1001,window=65535)/"User-Agent: "
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=46,ack=1001,window=65535)/"Mozilla\r\n\r\n"
+
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='RA',seq=1001,ack=18,window=65535)
+
+wrpcap('input.pcap', pkts)
--- /dev/null
+Test
+====
+
+Test series that tests if a RST that comes in before all data is ACK'd the
+unACK'd data is still reassembled and inspected, but does not trigger a GAP
+event.
+
+This test tests HTTP reassembly inspection of unack'd data with GAP.
--- /dev/null
+alert tcp any any -> any any (content:"User-Agent: Mozilla"; sid:1;)
+alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; threshold:type backoff, track by_flow, count 1, multiplier 10; classtype:protocol-command-decode; sid:2210048; rev:3;)
--- /dev/null
+requires:
+ min-version: 8
+
+checks:
+ - filter:
+ count: 1
+ match:
+ event_type: alert
+ alert.signature_id: 1
+ pkt_src: "stream (flow timeout)"
+ - filter:
+ count: 0
+ match:
+ event_type: alert
+ alert.signature_id: 2210048
+ - filter:
+ count: 1
+ match:
+ event_type: stats
+ stats.tcp.reassembly_gap: 0
--- /dev/null
+#!/usr/bin/env python
+from scapy.all import *
+
+pkts = []
+
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='S',seq=1,options=[('WScale', 14)])
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='SA',seq=1000,ack=2,options=[('WScale', 14)],window=65535)
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535)
+
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535)/"GET / HTTP/1.0\r\n"
+#pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=18,ack=1001,window=65535)/"Cookie: abcdef\r\n"
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=34,ack=1001,window=65535)/"User-Agent: "
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=46,ack=1001,window=65535)/"Mozilla\r\n\r\n"
+
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='RA',seq=1001,ack=18,window=65535)
+
+wrpcap('input.pcap', pkts)
--- /dev/null
+Test
+====
+
+Test series that tests if a RST that comes in before all data is ACK'd the
+unACK'd data is still reassembled and inspected, but does not trigger a GAP
+event.
+
+This test tests HTTP reassembly inspection of unack'd data with GAP in IPS mode.
--- /dev/null
+alert tcp any any -> any any (content:"User-Agent: Mozilla"; sid:1;)
+alert tcp any any -> any any (msg:"SURICATA STREAM reassembly sequence GAP -- missing packet(s)"; stream-event:reassembly_seq_gap; threshold:type backoff, track by_flow, count 1, multiplier 10; classtype:protocol-command-decode; sid:2210048; rev:3;)
--- /dev/null
+requires:
+ min-version: 8
+
+checks:
+ - filter:
+ count: 1
+ match:
+ event_type: alert
+ alert.signature_id: 1
+ pcap_cnt: 6
+ - filter:
+ count: 0
+ match:
+ event_type: alert
+ alert.signature_id: 2210048
+ - filter:
+ count: 1
+ match:
+ event_type: stats
+ stats.tcp.reassembly_gap: 0
--- /dev/null
+#!/usr/bin/env python
+from scapy.all import *
+
+pkts = []
+
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='S',seq=1,options=[('WScale', 14)])
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='SA',seq=1000,ack=2,options=[('WScale', 14)],window=65535)
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535)
+
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=2,ack=1001,window=65535)/"GET / HTTP/1.0\r\n"
+#pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=18,ack=1001,window=65535)/"Cookie: abcdef\r\n"
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=34,ack=1001,window=65535)/"User-Agent: "
+pkts += Ether(dst='05:04:03:02:01:00', src='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(src='1.1.1.1', dst='2.2.2.2')/TCP(dport=8080,sport=12345,flags='A',seq=46,ack=1001,window=65535)/"Mozilla\r\n\r\n"
+
+pkts += Ether(src='05:04:03:02:01:00', dst='00:01:02:03:04:05')/Dot1Q(vlan=6)/IP(dst='1.1.1.1', src='2.2.2.2')/TCP(sport=8080,dport=12345,flags='RA',seq=1001,ack=18,window=65535)
+
+wrpcap('input.pcap', pkts)