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

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.

Related

Receive a TCP SYN packet without sending a SYNACK response

I want to be able to receive SYN packets from a client, but not send back a SYNACK response. I have tried a few things. If you use raw sockets, it is possible to receive the full packet but linux kernel seems to automatically send back a FINACK packet. I found out that this was because I did not have a service actually listening to the port I was monitoring. My next step was to bind a socket to the port I was interested in, and use the listen() syscall to listen to that port, along with the raw socket. This approach results in the kernel automatically sending back a SYNACK rather than a FINACK. Is there anyway to receive a raw packet, and not send back an automated response? It seems that raw sockets can only snoop on packets, rather than actually handle them. I have also tried using a UDP server socket to listen to the target port, but I am still sending back an automatic FINACK.

Raw ICMP socket interaction with internal stack windows/linux

In regard to using ICMP raw socket like in this example
sd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
There's some important question I didn't find an answer anywhere in the documentation. As far as I understand the ICMP protocol is implemented
on kernel level ((by %SystemRoot%\System32\Drivers\Tcpip.sys driver windows) .
So how this kernel logic interacts with the raw user space socket willing to send and receive the ICMP packets defined as in example above?
Is ICMP logic canceled since RAW socket is open and OS gives the application full control of ICMP? Or they are working in parallel (inevitably creating the mess on the network). Can I tell OS which ICMP packets I would like to handle exactly?
Answers for both linux and windows are welcome.
By using the raw socket with IPPROTO_ICMP you only get copies of the ICMP packets which arrive at your host (see How to receive ICMP request in C with raw sockets). The ICMP-logic in the network stack is still alive and will handle ICMP-messages.
So you just need to pick the ICMP packets of your interest after you received them (e.g. with the corresponding ID in the ICMP header). In the receive buffer you get filled by calling recv() you also get the complete IP header.
Under Linux there is even a socket option (ICMP_FILTER) with which you can set a receive-filter for different ICMP packets.

Linux UDP Socket: why select()?

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.)

Linux TCP accept without SYN|ACK

I'm trying to write a TCP transparent proxy to run on Linux.
I want to, upon receipt of an incoming connection, initiate a corresponding outgoing connection, but only accept (SYN|ACK) the incoming connection if the outgoing connection is successful.
TCP_DEFERRED_ACCEPT doesn't do what I want -- it always sends a SYN|ACK.
The question is: how do I accept TCP connections, but defer the SYN|ACK, with the Linux sockets API?
You can do that with Linux, but not via the socket API. You would use the NFQUEUE target which allows you to redirect some packets to userspace and decide their fate from within your program.
Obiously, you'd still have to parse the packet in userspace, but searching for a few TCP flags should not be that hard and not require a complete TCP stack. And this way Linux still does the whole network job.
In your case, it would seem possible that you both use NFQUEUE and classical sockets API. The first will give you early decisions, the latter TCP stream data access. Although I never tried it.
See https://home.regit.org/netfilter-en/using-nfqueue-and-libnetfilter_queue/ for instance.

Linux: how to send TCP packet from specific port?

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.

Resources