Description
The implementation of published ports (redirected TCP streams), when going through the socket bound by the docker engine (not through iptables nat) interferes with TCP's half-duplex close sequence. The connection is closed prematurely and reset.
TCP allows closing half of the stream only. When an endpoint sends a FIN message, it means that the endpoint will no longer send any data but it may still receive data from the other endpoint (until the other endpoint sends a FIN message too).
https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Connection_termination
When the docker engine receives EOF (FIN) from the incoming connection, it closes immediately the two sockets with the system call close(), whereas it should only call shutdown(sock, SHUT_WR) on the outgoing socket. close() should be called only after the two sides of the channel are shut down and all the data is transmitted.
Steps to reproduce the issue:
- build the
tcp-bug-server image from:
FROM debian:jessie
RUN apt-get -y -qq update && apt-get -y -qq install socat
CMD ["socat", "TCP-LISTEN:1234,fork", "EXEC:echo hello"]
- build the
tcp-bug-client image from:
FROM debian:jessie
RUN apt-get -y -qq update && apt-get -y -qq install socat
CMD socat STDIO TCP:172.17.0.1:1234 </dev/null
- launch a capture
tcpdump -i docker0 -s 2000 -w /tmp/cap.dump
- run the server
docker run -d -p 1234:1234 tcp-bug-server
- run the client
docker run --rm tcp-bug-client
- open the capture in wireshark and select "Statistics" -> "Flow Graph" -> "TCP Flow"
Describe the results you received:
The client prints nothing on stdout
The wireshark flowgraph:
client docker server
FIN
------------------>
FIN, ACK
<------------------
ACK
------------------>
FIN
------------------>
PSH, ACK
<------------------
RST
------------------>
Describe the results you expected:
The client prints "hello" on stdout
The wireshark flowgraph:
client docker server
FIN
------------------>
ACK
<------------------
FIN
------------------>
PSH, ACK
<------------------
ACK
------------------>
PSH
<------------------
ACK
------------------>
FIN
<------------------
ACK
------------------>
FIN
<------------------
ACK
------------------>
Additional information you deem important (e.g. issue happens only occasionally):
happens every time
Output of docker version:
Client:
Version: 1.12.0
API version: 1.24
Go version: go1.6.3
Git commit: 209592a
Built: Wed Aug 3 14:21:36 2016
OS/Arch: linux/amd64
Server:
Version: 1.12.0
API version: 1.24
Go version: go1.6.3
Git commit: 209592a
Built: Wed Aug 3 14:21:36 2016
OS/Arch: linux/amd64
Output of docker info:
Containers: 28
Running: 10
Paused: 0
Stopped: 18
Images: 600
Server Version: 1.12.0
Storage Driver: overlay
Backing Filesystem: extfs
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: null overlay bridge host
Swarm: active
NodeID: 15jqcnhs5qwm3wiu6wvnpj2ph
Is Manager: true
ClusterID: 1yfrvoydx73ahwcuzoroo1nn3
Managers: 1
Nodes: 1
Orchestration:
Task History Retention Limit: 5
Raft:
Snapshot interval: 10000
Heartbeat tick: 1
Election tick: 3
Dispatcher:
Heartbeat period: 5 seconds
CA configuration:
Expiry duration: 3 months
Node Address: 172.17.42.1
Runtimes: runc
Default Runtime: runc
Security Options: seccomp
Kernel Version: 4.4.0-0.bpo.1-amd64
Operating System: Debian GNU/Linux 8 (jessie)
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 3.728 GiB
Name: halfoat
ID: DJOY:YSRX:QDV6:ZLD3:G7MH:SLXG:6MRI:K4Y5:MZ5W:XVYR:MMQN:ABKA
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
WARNING: No kernel memory limit support
Insecure Registries:
false
127.0.0.0/8
Description
The implementation of published ports (redirected TCP streams), when going through the socket bound by the docker engine (not through iptables nat) interferes with TCP's half-duplex close sequence. The connection is closed prematurely and reset.
TCP allows closing half of the stream only. When an endpoint sends a FIN message, it means that the endpoint will no longer send any data but it may still receive data from the other endpoint (until the other endpoint sends a FIN message too).
https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Connection_termination
When the docker engine receives EOF (FIN) from the incoming connection, it closes immediately the two sockets with the system call
close(), whereas it should only callshutdown(sock, SHUT_WR)on the outgoing socket.close()should be called only after the two sides of the channel are shut down and all the data is transmitted.Steps to reproduce the issue:
tcp-bug-serverimage from:tcp-bug-clientimage from:Describe the results you received:
The client prints nothing on stdout
The wireshark flowgraph:
Describe the results you expected:
The client prints "hello" on stdout
The wireshark flowgraph:
Additional information you deem important (e.g. issue happens only occasionally):
happens every time
Output of
docker version:Output of
docker info: