Linux UDP Socket: why select()? - linux

I am new to Linux socket programming. Here I have an basic question:
for UDP, why we need select()?
As UDP is stateless, so UDP server just handles whatever data it received. There will be no new socket created once a new client sends data, right?
if so, select() will be returned/notified once this socket has data arrived. So we don't need to go throughput all to check which socket is being notified (as there will be only one socket);
Is this true? non-blocking UDP socket + select() == blocking UDP socket.
Thanks!

The main benefit of select() is to be able to wait for input on multiple descriptors at once. So when you have multiple UDP sockets open, you put them all into the fd_set, call select(), and it will return when a packet is received on any of them. And it returns an fd_set that indicates which ones have data available. You can also use it to wait for data from the network while also waiting for input from the user's terminal. Or you can handle both UDP and TCP connections in a single server (e.g. DNS servers can be accessed using either TCP or UDP).
If you don't use select(), you would have to write a loop that continuously performs a non-blocking read on each socket. This is not as efficient, since it will spend lots of time performing unnecessary system calls (imagine a server that only gets one request a day, yet is continually calling recv() all day).
Your question seems to assume that the server can work with just one UDP socket. However, if the server has multiple IP addresses, it may need multiple sockets. UDP clients generally expect the response to come from the same IP they sent the request to. The standard socket API doesn't provide a way to know which IP the request was sent to, or to set the source address of the outgoing reply. So the common way to implement this is to open a separate socket bound to each IP, and use select() or epoll() to wait for a request on all of them concurrently. Then you send the reply through the same socket that the request was received on, and it will use that socket's bound IP as the source.
(Linux has socket extensions that make this unnecessary, see Setting the source IP for a UDP socket.)

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.

Receiving and filtering UDP packets with the same destination port from multiple peers

I have two independent network peers sending video data over UDP to a single host both using the same destination port.
e.g.
protocol src_addr src_port dst_addr dst_port
UDP peer1 ephemeral host1 5555
UDP peer2 ephemeral host1 5555
I can have a single socket receive both streams and dispatch the video data to the appropriate decode engine based on src_addr; but what is the best way to achieve the same result without a single receive socket (which is desirable because I would prefer both decodes to be independent applications)?
It feels like it should be possible because each video data stream is uniquely identified in the table above.
The primary issue is that bind() fails when the two sockets, in the two separate receive applications, attempt to bind to the same port.
Options:
1) SO_REUSEADDR and connect()
Can I use SO_REUSEADDR to allow both sockets to bind to the same port? Will a subsequent call to connect() filter the appropriate datagrams to the appropriate application? Or will all datagrams still be delivered to the first socket?
2) SO_REUSEPORT and connect()
SO_REUSEPORT seems to be used to achieve the above for, as an example, load balancing. How is a receiving socket selected? And will it respect connect()?
A quick look at the code in the Linux kernel (net/core/sock_reuseport.c) suggests it is selected randomly unless a Berkeley packet filter is set.
3) Berkeley packet filter
Is this a sensible approach?

UDP packets arriving on wrong sockets on Linux

I have two UDP sockets bound to the same address and connected to addresses A and B. I have two more UDP sockets bound to A and B and not connected.
This is what my /proc/net/udp looks like (trimmed for readability):
sl local_address rem_address
3937: 0100007F:DD9C 0300007F:9910
3937: 0100007F:DD9C 0200007F:907D
16962: 0200007F:907D 00000000:0000
19157: 0300007F:9910 00000000:0000
According to connect(2): "If the socket sockfd is of type SOCK_DGRAM, then addr is the address to which datagrams are sent by default, and the only address from which datagrams are received."
For some reason, my connected sockets are receiving packets that were destined for each other. eg: The UDP socket connected to A sends a message to A, A then sends a reply back. The UDP socket connected to B sends a message to B, B then sends a reply back. But the reply from A arrives at the socket connected to B and the reply from B arrives at the socket connected to A.
Why on earth would this be happening? Note that it happens randomly - sometimes the replies arrive at the correct sockets and sometimes they don't. Is there any way to prevent this or any situation under which connect is supposed to not work?
Ehm, as far as I can see there is no ordering guarantee.
From the man page:
SO_REUSEPORT (since Linux 3.9)
Permits multiple AF_INET or AF_INET6 sockets to be bound to an identical socket address. This option must be set on each socket (including the first socket) prior to calling bind(2) on the socket. To prevent port hijacking, all
of the processes binding to the same address must have the same effective UID. This option can be employed with both TCP and UDP sockets.
For TCP sockets, this option allows accept(2) load distribution in a multi-threaded server to be improved by using a distinct listener socket for each thread. This provides improved load distribution as compared to traditional
techniques such using a single accept(2)ing thread that distributes connections, or having multiple threads that compete to accept(2) from the same socket.
For UDP sockets, the use of this option can provide better distribution of incoming datagrams to multiple processes (or threads) as compared to the traditional technique of having multiple processes compete to receive datagrams on
the same socket.
So you're using something that is mainly seen as a option for servers (or in some cases clients, but ordering can never be guaranteed - especially in UDP) as a client.
I suspect your approach is wrong, and needs a rethink =)
PS. Just had a quick glance but IMHO it's a bug in your approach

Why does socketpair() allow SOCK_DGRAM type?

I've been learning about Linux socket programming recently, mostly from this site.
The site says that using the domain/type combination PF_LOCAL/SOCK_DGRAM...
Provides datagram services within the local host. Note that this
service is connectionless, but reliable, with the possible exception
that packets might be lost if kernel buffers should become exhausted.
My question, then, is why does socketpair(int domain, int type, int protocol, int sv[2]) allow this combination, when according to its man page...
The socketpair() call creates an unnamed pair of connected sockets in
the specified domain, of the specified type...
Isn't there a contradiction here?
I thought SOCK_DGRAM in the PF_LOCAL and PF_INET domains implied UDP, which is a connectionless protocol, so I can't reconcile the seeming conflict with socketpair()'s claim to create connected sockets.
Datagram sockets have "pseudo-connections". The protocol doesn't really have connections, but you can still call connect(). This associates a remote address and port with the socket, and then it only receives packets that come from that source, rather than all packets whose destination is the address/port that the socket is bound to, and you can use send() rather than sendto() to send back to this remote address.
An example where this might be used is the TFTP protocol. The server initially listens for incoming requests on the well-known port. Once a transfer has started, a different port is used, and the sender and receiver can use connect() to associate a socket with that pair of ports. Then they can simply send and receive on that new socket to participate in the transfer.
Similarly, if you use socketpair() with datagram sockets, it creates a pseudo-connection between the two sockets.

How do I prevent Linux kernel from responding to incoming TCP packets?

For my application, I need to intercept certain TCP/IP packets and route them to a different device over a custom communications link (not Ethernet). I need all the TCP control packets and the full headers. I have figured out how to obtain these using a raw socket via socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); This works well and allows me to attach filters to just see the TCP port I'm interested in.
However, Linux also sees these packets. By default, it sends a RST when it receives a packet to a TCP port number it doesn't know about. That's no good as I plan to send back a response myself later. If I open up a second "normal" socket on that same port using socket(PF_INET, SOCK_STREAM, 0); and listen() on it, Linux then sends ACK to incoming TCP packets. Neither of these options is what I want. I want it to do nothing with these packets so I can handle everything myself. How can I accomplish this?
I would like to do the same thing. My reason is from a security perspective… I am wanting to construct a Tarpit application. I intent to forward TCP traffic from certain source IPs to the Tarpit. The Tarpit must receive the ACK. It will reply with a SYN/ACK of its own. I do not want the kernel to respond. Hence, a raw socket will not work (because the supplied TCP packets are teed), I need to also implement a Divert socket. That's about all I know so far… have not yet implemented.

Resources