How can i simulate a connect from a non-blocking client to experience a EINPROGRESS error ?
What can i do from the server to return such error to the client (i.e tuning some tcp timers, raw socket server etc..)
When connecting to localhost TCP always connects immediately, hence connect() doesn't return EINPROGRESS.
You can simulate that in client by "pretending" that connect() returned EINPROGRESS and waiting till the client socket becomes ready for write (as if connected after EINPROGRESS). In fact, some libraries do just that for non-blocking connect() to avoid two different code paths for immediate and for slow connect.
I had to do something similar recently and I came across this thread. I used iptable rules to solve my problem. EINPROGRESS is not something that is returned by the server. If a connect can't complete immediately, the return code from connect is -1 and the errorno is set to EINPROGRESS. Once connect sends out the SYN packet, your connect will complete (given that you are connecting to a valid IP address, and everything else is okay with the network).
If you can change iptables on the client side, then the easiest way to simulate EINPROGRESS is to create an iptable rule to drop outgoing SYN packets to the server's IP address and port.
iptables -A OUTPUT -p tcp --tcp-flags SYN,ACK,FIN,RST SYN -d serverip --dport serverport -j DROP
Keep in mind that this only works if you don't want the connect to ever complete.
Related
I have two processes written in two different programming languages that exchange information via a local TCP connection. One process is starting the other but their lifetime must be shared, i.e. if one dies, so does the other and vice versa.
I would like to use the TCP connection as the mechanism to detect if the other side is crashing, but I'm not sure if it's safe. I wonder if there are cases where the connection could be closed for other reasons than one of process crashing or exiting.
Edit:
Ideally, the system needs to be portable across OS which is why TCP connections are used instead of Unix domain socket.
I know that it's possible to use administrative tools to kill the connection. What I want to know is if there are cases where in normal circumstances (both processes running fine) the connection would be close.
If the computers that are serving your processes are distant, then of course network problems along the way may cause problems, otherwise it's not trivial to close a connection. A tool such as "tcpkill" can close connections that originates or terminates on the local computer, and if you cross a firewall, then of course the firewall admin may close connections going through.
I think your scheme would work fairly well; if something causes the network connection to go down, then both your processes will terminate, so your worst case scenario would be excessive downtime - which I wouldn't expect from a connection through a normal network.
tcpkill: https://linux.die.net/man/8/tcpkill
You can use iptables to firewall the ports while the connection is running. By either ignoring packages or sending RSTs you could simulate different scenarios: remote host died, remote host closing the connection.
Examples:
# drop packages
iptables -p tcp --dport PORT_NUM -j DROP
# send RST
iptables -p tcp --dport PORT_NUM -j REJECT --reject-with tcp-reset
I've used the destination port above, to filter based on source port use --sport
If one side crashes (or closes/shuts-down its socket through any other means), the other one will see the socket as readable and get EOF on an attempted read.
You can inspect this behavior easily by observing a client-server nc pair, possibly with strace.
Server:
strace nc -l localhost 3333
Client:
strace nc localhost 3333
Whenever one side is killed (e.g., with Ctrl+C, Ctrl+\ or kill), the other side gets EOF (== a read of 0 bytes) ASAP.
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.
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.
I am working on a user space tcp stack (mostly just for fun) and I am having some trouble testing it against the unix tcp stack. Currently the only form of testing is done via unit tests. However, I want to test my tcp stack against a real kernel tcp stack. I tried the following setups without much success.
using raw sockets: I wrote a simple echo tcp server that accepts connection using the kernel tcp socket. The tcp server listens to port 8080 on localhost. My tcp client uses the user space tcp stack. However, the kernel sends a tcp rst whenever the client sends a syn to the server. It kind of work after I modified iptable to drop all tcp rst packets. However, even though the 3 way syn, syn+ack, ack handshake is established, the server cannot recv any packet that my client sends. I eventually gave up on raw sockets.
using tun/tap: Similarly the echo server uses kernel tcp socket and listens on localhost port 8080. The client opens a tap device. The tap device has an ip of 10.0.0.1 and my client assumes an ip of 10.0.0.2. I am able to ping 10.0.0.2 from my computer. However, when my client sends a syn to the tcp server over the tap device, the server does not respond.
Note: I am using ubuntu 12.04.
You can use the conntrack tool to try getting more information on why it's not working with using raw sockets. If for some reason the kernel gets confused about the state of the tcp connection, it may be deciding to reset it. You could try telling the kernel not to track connections to rule this out by setting a notrack rule in the raw table. Something like
iptables -t raw -A PREROUTING -p tcp --port 8080 -j NOTRACK
Try using tcpdump on the tun/tap device and iptables counts to see where the packet gets dropped. I would also try tun devices instead so you only have to worry about layer 3.
How to open a raw socket for sending from specific TCP port? I want to have all my connections always go from a range of ports below ephemerals.
If you are using raw sockets, then just fill in the correct TCP source port in the packet header.
If, instead, you are using the TCP socket interface (socket(), connect() and friends), then you can set the source port by calling the bind() system call for the client socket - exactly as you would to set the listening port for the server socket.
Making a tcp connection using raw sockets is somewhere between difficult and impossible; you'd need to implement the entire tcp protocol in your program AND also stop the kernel from sending its own replies to the packets (if the kernel has IP bound on that address on that interface).
This is probably not what you want. However, if you did want it, it is trivial to send tcp frames with any source port you want, as you get to specify it in the tcp header, which of course, if you're implementing your own TCP layer, you'll need to understand.