Friday, June 27, 2014

How to emulate network timeout?

How to emulate network timeout?

Before march into how to emulate network timeout, we have to understand the details of network timeout first.

Socket Timeout

We already knew that there are 3 times of handshake before establish a tcp connection.
- client send 'SYN'.(client: SYN_SENT)
- server response 'SYN'+'ACK'(client: SYN_SENT, server:SYN_SENT)
- client response 'ACK'(client:ESTABLISHED, server(got ACK):ESTABLISHED)

Client Connects to a Nonexistent Port

In this case, host's IP is valid, however the tcp port is nonexistent, and in general server will response 'connection refused'.

Client Connects to a Nonexistent IP

In this case, client will get 'host unreachable'.

Packet Lost During Establishing Connection

As there are 3 times of handshake, each packet maybe lost in network.

SYN of client lost

As no 'ACK' of 'SYN', client will keep resending 'SYN'. If the process of resending fail finally, connection timeout occurs.

SYN+ACK of server lost

As no 'ACK' of server's 'SYN', server will keep resending 'SYN'. If the process of resending fail finally, connection timeout occurs at server side. Also client can't get 'ACK', it behaves like last case.

ACK of client lost

In this case, client will regard that connection has been established successfully, however the state of server is still SYN_SENT, so if client try to send data, it won't reach the server, and as no ACK of sending, client will retransmit, and finally get connection timeout.
Refer to 深入理解socket网络异常

Emulate Socket Timeout

On *nix OS, we can achieve this by command 'iptables'. A full iptables reference can be found here and here
By means of 'iptables', we will emulate 2 kinds of timeout. Let's IGPE is deployed on a remote server, and IGPE port is 9090.

Emulate Connection Timeout

Connection timeout means no connection established at all, in general thay says the handshakes of TCP fails. The client can be very sure that no any request data reaches the backend if connection timeout.
Use below command to drop the response SYN packet(flag SYN set).
iptables -A OUTPUT -p tcp -m tcp --tcp-flags SYN SYN --sport 9090 -j DROP
As any pakcet lost during handshake will trigger connection timeout, we can approach this by many means.
The arguments of --tcp-flags is a little confused, i am not completedly understood, you can refer to the manual page. In above rule, I am trying to drop all outgoing packets whose 'SYN' flag has been set, and source tcp port is 9090.
Use below command to view your rules:
iptables -L -v

And then remember to use below command to clear all your rules:
iptables -F

Emulate Read Timeout

Read timeout means the connection has established successfully, however the client fail to get response(wail to timeout). In this case, the client can't be sure whether the request data has reached the backend or not(or say whether the request has been handled by the backend or not).
Use below command to drop the data response packet(flag PSH set).
iptables -A OUTPUT -p tcp -m tcp --tcp-flags PSH PSH --sport 9090 -j DROP
- PSH flag means there is data transfer in packet, not only a control packet.(oh NO, PSH aims to inform TCP buffer to send data immediately, no need to wait buffer is fulll, refer to
- I only wanna drop the response data packet, and emulate read timeout by this way.

The Retionale

In a client/server deployment, the server port will be fixed however the client tcp port is randomly picked. To a INPUT chain(the client request), the source port is client tcp port, however to a OUTPUT chain(server response), the source port is server tcp port. This must be clarified.
In my first try, I try to emulate connection timeout by below rule:
iptables -A INPUT -p tcp -m tcp --dport 9090 -j DROP

It won't result in a connction timeout, as all incoming packets will be dropped, that says no 'ACK' packet of request 'SYN' will be returned, in this case client will regard that the host is unreachable(not connection timeout). The key of emulating connection timeout is let client get the 'ACK' pakcet, however no 'SYN' packet from server, in this case, client will keep issuing 'SYN' packets and at final regard it as timeout.
If try to emulate read timeout, we must affect the OUTPUT chain.
Also seem there are build-in tool in linux can emulate these 2 situations, refer to netem

Referenced Documents

1 comment:

Jonathan Els said...

Just to clarify:

--tcp-flags SYN SYN

This matches SYN packets that have the SYN bit set.

Compared to:

--tcp-flags ALL PSH

Match ALL packets (aka SYN,ACK,FIN,RST,URG,PSH) that have the PSH bit set.