difference between socket failing with EOF and connection reset - linux

For testing a networking application, I have written an asio port "proxy": it listens on a socket for the application client activity and sends all incoming packets to another socket where it is listened to by the application server, and back.
Now when either the application or the server disconnect for various reasons, the "proxy" usually gets an EOF but sometimes it receives a "connection reset".
Hence, the question: when does a socket fail with a "connection reset" error?

A TCP connection is "reset" when the local end attempts to send data to the remote end and the remote end answer with a packet with the RST flag set (instead of ACK). This almost always happens because the remote end doesn't know about any TCP connection that matches the remote&local addresses and remote&local port numbers. Possible reasons include:
The remote end has been rebooted
A state-tracking firewall somewhere in the path has been rebooted/changed/added/removed
A load balancer has incorrectly directed the TCP connection to a different node than the one it was supposed to go to.
The remote IP address has changed hands (the new owner doesn't know anything about TCP connections belonging to the old owner).
The remote end considers that the TCP connection has been closed already (but somehow the local end doesn't agree).
Note that if the remote end answers the initial (SYN) packet in a TCP connection with a RST packet, it is considered "Connection refused" instead of "Connection reset by peer".

Related

TCP server ignores incoming SYN

I have a tcp server running. A client connects to the server and send packet periodically. For TCP server, this incoming connections turns to be CONNECTED, and the server socket still listens for other connections.
Say this client suddenly get powered off, no FIN sent to server. When it powers up again, it still use the same port to connect, but server doesn't reply to SYNC request. It just ignores incoming request, since there exists a connection with this port.
How to let server close the old connection and accept new one?
My tcp server runs on Ubuntu 14.04, it's a Java program using ServerSocket.
That's not correct, a server can accept multiple connections and will accept a new connection from a rebooted client as long as it's connecting from a different port (and that's usually the case). If your program is not accepting it it's because you haven't called accept() a second time. This probably means that your application is only handling one blocking operation per time (for example, it might be stuck in a read() operation on the connected socket). The solution for this is to simultaneously read from the connected sockets and accept new connections. This might be done using an I/O multiplexer, like select(), or multiple threads.

What happens to TCP socket when IP address changes?

Is there any error on a socket when writing to it after IP address change?
In my I'm using TCP socket, both read/write (non-passive), no TCP or application keep-alive.
To inspect this case I use socat to connect to a simple echo server on my local network. The connection is OK until I change the client IP address on my router and restart the network interface.
At this point, I can write to a socket without any errors despite the IP of the client was changed, but no messages are being delivered anymore. I wait for some minutes and change the IP back. All the 'stashed' messages which were unable to be sent are being sent.
As far as I understand, when client IP was changed TCP connection does not exist anymore.
Why there are no errors when writing to the socket when IP was changed? Is this specific to a Linux TCP stack or specified by TCP/IP?
A TCP connection is defined by source IP, source port, destination IP, and destination port. Changing the client's IP address on your router does not cause the connection on your client and server to cease to exist immediately; however, if you leave the router in this state long enough, the connection will eventually cease to exist after certain amount of retries and timeouts have occurred. The exact amount is determined via configurable kernel parameters both on your client and on your echo server. You can inspect these parameters with sysctl -a | grep tcp
After you've changed the client's IP address on your router, the client is still able to send packets to the server, and the server is also able to receive these packets, but the server's attempt to reply/acknowledge back to the client is unable to be routed back to the client. This leads to retries up to a certain limit on the client (which is why you saw no errors on the client side). Once you've reverted the client's IP back on your router, the server is able to communicate with the client again as the router is now able to correctly route the server's packet to the client.
This retry behavior is not specific to the Linux TCP stack. rfc 2988 defines the standard algorithm that senders are required to use to compute and manage their retransmission timer.

Simultaneous TCP termination and subsequent connect(): EADDRNOTAVAIL

My company releases a special TCP stack for special purposes and I'm tasked with implementing RFC793 compliant closing sequence. One of the unit tests has a server working on top of the special TCP stack talking to a normal Linux TCP client, and I'm running into some strange behaviour that I'm not sure whether is caused by programming error on my part or is to be expected.
Before my work started, we used to send a RST packet when the user application calls close(). I've implemented the FIN handshake, but I noticed that in the case of simultaneous TCP termination (FIN_WAIT_1 -> CLOSING -> TIME_WAIT on both ends, see the picture), the standard Linux TCP client cannot connect to the same destination address and port again, with connect() returning with EADDRNOTAVAIL, until after TIME_WAIT passes into CLOSED.
Now, the standard Linux client application sets the option SO_REUSEADDR, binds the socket to port 8888 each time, and connects to destination port 6666. My question is, why does bind() succeed and why does connect() fail? I would have thought SO_REUSEADDR could take over a local TIME_WAIT port, which it did, but what does connect() have against talking to the destination-ip:6666 again?
Is my code doing something it shouldn't or is this expected behaviour?
I can confirm no SYN packet for the failed connect() makes it out of the client machine at all. I've attached a screenshot of the FIN handshake for the above session.
Your previous implementation used RST to end the connection. Receipt of an RST packet immediately removes the connection from the active connection table. That's because there is no further possibility of receiving a valid packet on that connection: the peer has just told your system that that session is not valid.
If you do a proper session termination with FIN, on the other hand, there is the last packet problem: how do you know for sure whether the peer actually received the last acknowledgment you sent to their FIN (this is the definition of TCP's TIME_WAIT state)? And if the peer didn't receive it, they might validly send another copy of the FIN packet which your machine should then re-ACK.
Now, your bind succeeds because you're using SO_REUSEADDR, but you still cannot create a new connection with the exact same ports on both sides because that entry is still in your active connection table (in TIME_WAIT state). The 4-tuple (IP1, port1, IP2, port2) must always be unique.
As #EJP suggested in the comment, it is unusual for the client to specify a port, and there is typically no reason to. I would change your test.

Multiple FIN packets received by server

I am running a port forwarding proxy on a linux box. All the connections from the browser are rerouted to a different port using the proxy.
Whenever the proxy receives (recv()) 0 bytes, I close the connection with the outer world (opened through proxy) using shutdown. When that connection is closed, I close the connection with the browser. The arrangement looks like follows:
Connection Out Local Connection
Outer World <-----> Forward Proxy(Local Box)<-------> Client(Local Box)
However, I receive multiple data packets of length 0 on "local connection" for the same socket before it is closed. This happens when proxy is trying to close the connection with the outer world.
My understanding is TIME_WAIT value is 2*MSL and that comes out to be pretty high,(hundreds of seconds). However, I see multiple 0 byte packets in a fraction of a second. Am I doing something wrong? Or my understanding is wrong.
Thanks

TCP/IP basics: Destination port relevance

Ok this is kind of embarassing but I just have a rather "noob" question.
In a client server TCP communications, where my system is a client accessing a remote server at say Port XX, isnt the client opening a random port YY in its system to talk to remote port XX?
So when we code we do specify the destination port XX right?
For the client, the port YY itself is chosen when the socket is created, isnt it?
Is there anyway I could monitor/restrict/control any client talking to a particular server?(like say clients talking to servers at specific serving ports??)
Is there any IPTABLE rule or some firewall rule restricting the client?
Can this be done at all??
Are destination ports saved in the socket structures? If so where??
Thanks!
First, server side creates a listening socket, with the chain of socket(2), bind(2), and listen(2) calls, then waits for incoming client connection requests with the accept(2) call. Once a client connects (socket(2) and then connect(2) on the client side) and the TCP/IP stacks of the client and the server machines complete the three way handshake, the accept(2) returns new socket descriptor - that's the server's end of the connected socket. Both bind(2) on the server side, and connect(2) on the client side take server's address and port.
Now, the full TCP connection is described by four numbers - server address, server port, client address, and client port. The first two must obviously be known to the client prior to the connection attempt (otherwise, where do we go?). The client address and port, while could be specified explicitly with the bind(2), are usually assigned dynamically - the address is the IP address of the outgoing network interface, as determined by the routing table, and the port selected out of range of ephemeral ports.
The netstat(8) command shows you established connections. Adding -a flag lets you see listening sockets, -n flag disables DNS and service resolution, so you just see numeric addresses and ports.
Linux iptables(8) allows you to restrict where clients are allowed to connect to. You can restrict based on source and destination ports, addresses, and more.
You can get socket local binding with getsockname(2) call, remote binding is given by getpeername(2).
Hope this makes it a bit more clear.
Yes you can create a firewall rule to prevent outbound TCP connections to port XX. For example, some organizations prevent outbound TCP port 25, to prevent spam being sent from network PCs to remote SMTP servers.

Resources