google / google/gopacket

tcpassembly and reassembly: improper RST handling

Open
#425 1 comment 5 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
6.8k
Forks
1.2k
PR merge metrics
No merged PRs in 30d

Description

I have two test cases:
* Client sends SYN, the server responds with RST/ACK. This is what usually happens when somebody tries to connect to a closed port. http://cdn.big.dong.solutions/a2441ae2-62c4-4cb7-b2dc-fc26e3f40902/syn_reset.pcap
* Client and server do proper handshake, exchange some data, and then connection is terminated with RST from one side. No further packets come. Happens, among other cases. when connection is closed when there's still data in receive queue. http://cdn.big.dong.solutions/a2441ae2-62c4-4cb7-b2dc-fc26e3f40902/reset_session.pcap

I have written simple code that traces the reassembly process. https://gist.github.com/WGH-/8d316e46e9a198440c213513c798b64c

In the first scenario, trace looks like this:
```
2018/03/06 18:45:09 packet 1: calling AssembleWithTimestamp()
2018/03/06 18:45:09 stream #1: (created)
2018/03/06 18:45:09 stream #1: Reassembled
2018/03/06 18:45:09 packet 2: calling AssembleWithTimestamp()
2018/03/06 18:45:09 calling FlushAll
2018/03/06 18:45:09 stream #1: ReassemblyComplete
```
RST packet doesn't cause stream to be closed/aborted. It's only closed when FlushAll is explicitly called. Any port scan will cause tcpreassembly code to create a lot of streams that will never be cleaned up, unless flush is regularly, even though they can be properly cleaned up right away.

The second scenario:
```
2018/03/06 18:48:02 packet 1: calling AssembleWithTimestamp()
2018/03/06 18:48:02 stream #1: (created)
2018/03/06 18:48:02 stream #1: Reassembled
2018/03/06 18:48:02 packet 2: calling AssembleWithTimestamp()
2018/03/06 18:48:02 stream #2: (created)
2018/03/06 18:48:02 stream #2: Reassembled
2018/03/06 18:48:02 packet 3: calling AssembleWithTimestamp()
2018/03/06 18:48:02 packet 4: calling AssembleWithTimestamp()
2018/03/06 18:48:02 stream #1: Reassembled
2018/03/06 18:48:02 packet 5: calling AssembleWithTimestamp()
2018/03/06 18:48:02 packet 6: calling AssembleWithTimestamp()
2018/03/06 18:48:02 stream #2: Reassembled
2018/03/06 18:48:02 stream #2: ReassemblyComplete
2018/03/06 18:48:02 calling FlushAll
2018/03/06 18:48:02 stream #1: ReassemblyComplete
```
In this case, RST successfully terminates stream, but only in one direction. The other direction is cleaned up only when FlushAll is called.

For comparison, this is how the trace looks like when connection is closed with proper exchange of FIN packets: http://cdn.big.dong.solutions/a2441ae2-62c4-4cb7-b2dc-fc26e3f40902/normal_session.pcap
```
2018/03/06 19:09:58 packet 1: calling AssembleWithTimestamp()
2018/03/06 19:09:58 stream #1: (created)
2018/03/06 19:09:58 stream #1: Reassembled
2018/03/06 19:09:58 packet 2: calling AssembleWithTimestamp()
2018/03/06 19:09:58 stream #2: (created)
2018/03/06 19:09:58 stream #2: Reassembled
2018/03/06 19:09:58 packet 3: calling AssembleWithTimestamp()
2018/03/06 19:09:58 packet 4: calling AssembleWithTimestamp()
2018/03/06 19:09:58 stream #1: Reassembled
2018/03/06 19:09:58 packet 5: calling AssembleWithTimestamp()
2018/03/06 19:09:58 packet 6: calling AssembleWithTimestamp()
2018/03/06 19:09:58 stream #2: Reassembled
2018/03/06 19:09:58 packet 7: calling AssembleWithTimestamp()
2018/03/06 19:09:58 packet 8: calling AssembleWithTimestamp()
2018/03/06 19:09:58 stream #1: Reassembled
2018/03/06 19:09:58 stream #1: ReassemblyComplete
2018/03/06 19:09:58 packet 9: calling AssembleWithTimestamp()
2018/03/06 19:09:58 stream #2: Reassembled
2018/03/06 19:09:58 stream #2: ReassemblyComplete
2018/03/06 19:09:58 packet 10: calling AssembleWithTimestamp()
2018/03/06 19:09:58 calling FlushAll
```
In this case, streams are cleaned up without a call to FlushAll.

Even though reassembly module seems to be more advanced than tcpassembly, it suffers from the same problem. https://gist.github.com/WGH-/ddd6390f37ceb7455e4f22b4ee5eeb9f

```
2018/03/06 19:13:41 packet 1: calling AssembleWithTimestamp()
2018/03/06 19:13:41 stream #1: (created)
2018/03/06 19:13:41 stream #1: Accept
2018/03/06 19:13:41 stream #1: ReassembledSG
2018/03/06 19:13:41 packet 2: calling AssembleWithTimestamp()
2018/03/06 19:13:41 stream #1: Accept
2018/03/06 19:13:41 calling FlushAll
2018/03/06 19:13:41 stream #1: ReassemblyComplete
```
```
2018/03/06 19:13:54 packet 1: calling AssembleWithTimestamp()
2018/03/06 19:13:54 stream #1: (created)
2018/03/06 19:13:54 stream #1: Accept
2018/03/06 19:13:54 stream #1: ReassembledSG
2018/03/06 19:13:54 packet 2: calling AssembleWithTimestamp()
2018/03/06 19:13:54 stream #1: Accept
2018/03/06 19:13:54 stream #1: ReassembledSG
2018/03/06 19:13:54 packet 3: calling AssembleWithTimestamp()
2018/03/06 19:13:54 stream #1: Accept
2018/03/06 19:13:54 packet 4: calling AssembleWithTimestamp()
2018/03/06 19:13:54 stream #1: Accept
2018/03/06 19:13:54 stream #1: ReassembledSG
2018/03/06 19:13:54 packet 5: calling AssembleWithTimestamp()
2018/03/06 19:13:54 stream #1: Accept
2018/03/06 19:13:54 packet 6: calling AssembleWithTimestamp()
2018/03/06 19:13:54 stream #1: Accept
2018/03/06 19:13:54 stream #1: ReassembledSG
2018/03/06 19:13:54 calling FlushAll
2018/03/06 19:13:54 stream #1: ReassemblyComplete
```
```
2018/03/06 19:14:08 packet 1: calling AssembleWithTimestamp()
2018/03/06 19:14:08 stream #1: (created)
2018/03/06 19:14:08 stream #1: Accept
2018/03/06 19:14:08 stream #1: ReassembledSG
2018/03/06 19:14:08 packet 2: calling AssembleWithTimestamp()
2018/03/06 19:14:08 stream #1: Accept
2018/03/06 19:14:08 stream #1: ReassembledSG
2018/03/06 19:14:08 packet 3: calling AssembleWithTimestamp()
2018/03/06 19:14:08 stream #1: Accept
2018/03/06 19:14:08 packet 4: calling AssembleWithTimestamp()
2018/03/06 19:14:08 stream #1: Accept
2018/03/06 19:14:08 stream #1: ReassembledSG
2018/03/06 19:14:08 packet 5: calling AssembleWithTimestamp()
2018/03/06 19:14:08 stream #1: Accept
2018/03/06 19:14:08 packet 6: calling AssembleWithTimestamp()
2018/03/06 19:14:08 stream #1: Accept
2018/03/06 19:14:08 stream #1: ReassembledSG
2018/03/06 19:14:08 packet 7: calling AssembleWithTimestamp()
2018/03/06 19:14:08 stream #1: Accept
2018/03/06 19:14:08 packet 8: calling AssembleWithTimestamp()
2018/03/06 19:14:08 stream #1: Accept
2018/03/06 19:14:08 stream #1: ReassembledSG
2018/03/06 19:14:08 packet 9: calling AssembleWithTimestamp()
2018/03/06 19:14:08 stream #1: Accept
2018/03/06 19:14:08 stream #1: ReassembledSG
2018/03/06 19:14:08 stream #1: ReassemblyComplete
2018/03/06 19:14:08 packet 10: calling AssembleWithTimestamp()
2018/03/06 19:14:08 stream #1: Accept
2018/03/06 19:14:08 calling FlushAll
```

I will likely try to fix this and submit an PR, but first, I'd like to discuss this a bit to make sure my conclusions are correct.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.