TCP Packet Mangling using NFQUEUE - linux

I am trying to solve the below issue,
I have a iptables rule in my output chain which says that if the packet matches certain criteria, then queue it and send it to userspace using NFQUEUE
The userspace program receives it,and once it recieves it, it checks if the packet is a tcp packet and if yes, it modifies the content of the packet
After Modifying it, it sends out and I am able to see that till now it works properly, I was able to re-calculate the checksum and verify it and update the length of the packet and everything gets properly reflected and I am able to confirm it using wireshark and I am also able to see that the packet is reaching the destination. The packet I am modifying is HTTP GET Packet.
The Intial TCP handshake happens and after the intial handshake, I am sending out the modified HTTP GET Packet and I am getting a response back from the server, but after this, the client for some reason generates a TCP RST packet and sends it to the destination, I am not sure why this happens, Earlier while googling, people had reported it might be due to sequence number disorder, but in my case, since I am modifying the first packet after the TCP Handshake, the sequence number will be the same as that of my last ACK packet belonging to the TCP Handshake.
I am suspecting that some part of the kernel module is caching the length of the HTTP GET request packet, and once I modify it, and update the length, the cached part is not getting updated, and as a reason, the client is sending the TCP RST Packet.
Can some one help me out with the above scenario.

The problem with this is that changing the length of a TCP packet which is part of an active flow messes up the sequence number code, which causes whichever side of the connection that notices to reset the connection. See the details in RFC 793 section 3.4

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.

Linux Raw Sockets: Block Packets?

I've written my own packet sniffer in Linux.
I open a socket with socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) and then process the Ethernet packets - unpacking ARP packets, IP packets (and ICMP / TCP / UDP packets inside those).
This is all working fine so far.
Now I can read packets like this - and I can also inject packets by wrapping up a suitable Ethernet packet and sending it.
But what I'd like is a means to block packets - to consume them, as it were, so that they don't get further delivered into the system.
That is, if a TCP packet is being sent to port 80, then I can see the packet with my packet sniffer and it'll get delivered to the web server in the usual fashion.
But, basically, I'd like it that if I spot something wrong with the packet - not coming from the right MAC address, malformed in some way, or just breaking security policy - that I can just "consume" the packet, and it won't get further delivered onto the web server.
Because I can read packets and write packets - if I can also just block packets as well, then I'll have all I need.
Basically, I don't just want to monitor network traffic, but sometimes have control over it. E.g. "re-route" a packet by consuming the original incoming packet and then writing out a new slightly-altered packet to a different address. Or just plain block packets that shouldn't be being delivered at all.
My application is to be a general "network traffic management" program. Monitors and logs traffic. But also controls it too - blocking packets as a firewall, re-routing packets as a load balancer.
In other words, I've got a packet sniffer - but if it sniffs something that smells bad, then I'd like it to be able to stop that packet. Discard it early, so it's not further delivered anywhere.
(Being able to alter packets on the way through might be handy too - but if I can block, then there's always the possibility to just block the original packet completely, but then write out a new altered packet in its place.)
What you are looking for is libnetfilter_queue. The documentation is still incredibly bad, but the code in this example should get you started.
I used this library to develop a project that queued network packets and replayed them at a later time.
A bit of a tangent, but it was relevant when I was resolving my problem. Blocking raw packets is relatively complicated, so it might make sense to consider doing that at a different layer. In other words, does your cloud provider let you set up firewall rules to drop specific kind of traffic?
In my case it was easier to do, which is why I'm suggesting such a lateral solution.

TCP strange RST packet terminating connection

The question is we have the following setup and we have noticed sometime client sends RST packet to terminate initial TCP handshake connection and application gets a timeout.
[10.5.8.30]------[Linux FW]-------[10.5.16.20]
Wireshark:
You can see in Wireshark RST packet, I thought its FW sending RST but in capture packet coming from 10.5.8.30 so what could be wrong here? why connection getting reset randomly, if I try next time then it will work.
The fact that the source IP for the RST packet is 10.5.8.30 doesn't mean that it really came from 10.5.8.30.
There are firewalls and various other intermediary devices that forge such packets. Try capturing on both ends to check whether 10.5.8.30 did, in fact, send the RST. It doesn't make sense for a client to send a TCP Syn and then a RST.

Can TCP RST packet reduce the connection timeout?

As a way to learn how raw sockets work, I programmed a dummy firewall which drops the packets based on the TCP destination port. It is working but the problem is that the client retries for quite some time until the time out is finally reached.
I was wondering if perhaps the client retries for so long because it does not receive any answer. In that case, would it help if the firewall replies with a TCP RST to the TCP SYNC messages from the client? If not, is there any way to force the client to stop retrying (not reducing the timeout time in the Linux but more, getting a specific answer to its packets which will make the client stop)?
You can think of your firewall as the same case as if the port were closed on the host OS. What would the host OS's TCP/IP stack do?
RFC 793 (original TCP RFC) has the following to say about this case:
If the connection does not exist (CLOSED) then a reset is sent
in response to any incoming segment except another reset. In
particular, SYNs addressed to a non-existent connection are rejected
by this means.
You should read the TCP RFCs and make sure your TCP RST packet conforms to the requirements for this case. A malformed RST will be ignored by the client.
RFC 1122 also indicates that ICMP Destination Unreachable containing codes 2-4 should cause an abort in the connection. It's important to note the codes because 0, 1, and 5 are listed as a MUST NOT for aborting the connection
Destination Unreachable -- codes 2-4
These are hard error conditions, so TCP SHOULD abort
the connection.
Your firewall is behaving correctly. It is a cardinal principle of information scurity not to disclose any information to the attacker. Sending an RST would disclose that the host exists.
There were firewalls that did that 15-20 years ago but there were frowned on. Nowadays they behave like yours: they just drop the packet and do nothing in reply.
It is normal for the client to retry a few times before giving up if there is no response, but contrary to what you have been told in comments, a client will give up immediately with 'connection refused' if it receives an RST. It only retries if there is no response at all.

Bypass TCP three way handshaking?

Is it possible to make a system call or write a kernel module to craft a tcp connection right into ESTABLISHED state without going over the three way handshaking process, assuming the correct SYN-seq and ack number are provided dynamically?
You may like to have a look at TCP fast open, which modern Linux kernels implement:
TCP Fast Open (TFO) is an extension to speed up the opening of successive Transmission Control Protocol (TCP) connections between two endpoints. It works by using a TFO cookie (a TCP option) in the initial SYN packet to authenticate a previously connected client. If successful, it may start sending data to the client before the receipt of the final ACK packet of the three way handshake is received, skipping a round trip and lowering the latency in the start of transmission of data.

Resources