Read UDP/TCP payload with divert socket - c

I need to intercept/redirect TCP and UDP packets that have its payloads matching some regex patterns and also get original destination address and port.
I can't just redirect TCP and UDP packets to my application by the use of DSTNAT on firewall (and splice() if don't match patterns) because that wouldn't allow me to get their original destination addresses and ports from before they are changed/translated.
So I read about divert sockets and they look promising. I'm in doubt however, as I couldn't find anywhere how much an application can read of a packet received on a divert socket. Is it possible to read entire packet (including TCP and UDP payload) or just its headers? Is entire packet sent to divert socket or just first received fragment (maybe limited by MTU/MRU or how much send() could push on single call on other end...)?
If it matters, the firewall I'm going to use for diverting packets is ipfw.

Related

How does the AF_PACKET socket work in Linux?

I am trying to write a C sniffer for Linux, and understand the actions happening in the kernel while sniffing.
I am having troubles finding an answer for the following question:
If I initialize my socket in the following way:
sock_raw = socket(AF_PACKET , SOCK_RAW , htons(ETH_P_ALL));
What happens in the kernel? How am I seeing all the incoming and outgoing packets, but not "hijacking" them? Because what I have understood do far is that when the kernel receives a packet, it sends it to the relevant protocol handler function. Therefore I can't understand - does the kernel clone the packet and sends it in addition to the socket I opened?
What happens in the kernel?
The kernel simply duplicates the packets as soon as it receives them from the physical layer (for incoming packets) or just before sending them out to the physical layer (for outgoing packets). One copy of each packet is sent to your socket (if you use ETH_PH_ALL then you are listening on all interfaces, but you could also bind(2) to a particular one). After a copy is sent to your socket, the other copy then continues being processed like it normally would (e.g. identifying and decoding the protocol, checking firewall rules, etc).
How am I seeing all the incoming and outgoing packets, but not "hijacking" them?
In order for hijacking to happen, you would need to write data to the socket injecting new packets (accurately crafted depending on the protocol you want to hijack). If you only read incoming packets, you are merely sniffing, without hijacking anything.
does the kernel clone the packet and sends it in addition to the socket I opened?
Yes, that's basically what happens. This image could help you visualize it.
man 7 packet also describes this:
Packet sockets are used to receive or send raw packets at the device driver (OSI Layer 2) level. They allow the user to implement protocol modules in user space on top of the physical layer.
The socket_type is either SOCK_RAW for raw packets including the link-level header or SOCK_DGRAM for cooked packets with the link-level header removed. The link-level header information is available in a common format in a sockaddr_ll structure. protocol is the IEEE 802.3 protocol number in network byte order. See the <linux/if_ether.h> include file for a list of allowed protocols. When protocol is set to htons(ETH_P_ALL), then all protocols are received. All incoming packets of that protocol type will be passed to the packet socket before they are passed to the protocols implemented in the kernel.

How to duplicate UDP packets to two or more sockets

I'm attempting to have two daemons running on the same port and IP but one is a server and the other is a client. Is there a method using socket options that would allow each socket to have a copy of the packet and let the daemons filter out the messages based on the protocol? It looks like reuse address blocks the first configured port and reuse port might just balance the packet between the two daemons.
Otherwise, I guess create another daemons to read the socket and send the packets to the correct daemon.
Thanks
You are correct at the end, you will need to have a third part that binds to the port and forwards the packets to the correct daemon.
The other way to do it would be to use three ports and use a firewall to redirect from the front end port to the backend ports; but that is a lot more complicated and not portable. But in the end you could use QOS or something. There is a wide range of possible types of use case behind the word protocol.
If the UDP packets you are receiving are multicast or broadcast packets, then you can set SO_REUSEADDR (and, for BSD-based OS's, SO_REUSEPORT) on the socket (using setsockopt()) before bind()-ing the socket, and then both sockets will receive a copy of each incoming UDP packet. (If the UDP packets are regular old unicast packets, OTOH, then doing the above will result in each received packet being received by only one of the two UDP sockets, which isn't what you want).
Note, however: You refer to the two daemons as being a "client" and a "server" -- the implication of those terms is that the two daemons are going to communicate with each other. If that is the case, then the typical approach would be to have the server-daemon bind to a well-known port number, and the client-daemon could bind to any port number (e.g. it could pass 0 as the port-number to bind(), and let the OS choose an available port-number for it). Then the client-daemon could start the conversation by sending one or more UDP packets to the server's well-known port number, and the server can find out which port the client is sending from (and therefore what port to send reply packets to) by examining the fifth argument of its recvfrom() call. In this case there is no need for the two programs to bind to the same port, and therefore no need for packet-forwarding.

TCP in C Programming

I want to know how a client or server gets an acknowledgement packet from a client or server after sending a packet in TCP Channel in C programming.
Why don't I need to handle this in code? How exactly does the client receive the acknowledgement packet, if it sends a data packet to server? Does this happen internally?
The TCP protocol is designed to provide a stream protocol. The typical programming interface is the socket interface where you can give a chunk of data that the protocol stack will transfer to the receiver. The actual implementation hides when the data has been queued in the receiving protocol stack or has been handed off to the receiving application. You would have make this distinction.
Sou what you apparently want is a signal mechanism to know, that and when the client has read the data from the protocol stack. This can be done by designing and implementing a protocol on top of the TCP protocol. When one side doesn't have to send meaningful data it sends a heartbeat message. This message indicates that the TCP connection is still alive.
Regarding your questions:
Why don't I need to handle this in code? Because the underlying layer has it done for your.
How exactly does the client receive the acknowledgement packet, if it sends a data packet to server? You don't need to care as long as you don't need a heartbeat. TCP provides you a stream interface similar like the interface for file I/O. You don't ask, when the data has left the disk cache, do you? When you start to re-implement internas you will have to define what about reassemblies, Nagle-algorithm and many other nasty things. Never implement TCP if you have another choice.
Does this happen internally? Yes, fortunately.

Debugging multicast reception

I'd like to debug multicast reception by the Linux kernel, because I'm not receiving any packets. Let me be more specific: I'm building a flexible userland transport mode network daemon. One of the options of running it, is using UDP sockets. One of the use cases, is to transport UDP packets that go to multicast addresses.
So I end up with UDP packets to a multicast destination, transported by a UDP packet to the same multicast destination. That's asking for trouble, I know, but I get away with it: using SO_BINDTODEVICE, I can pretty much cheat my way through the routing table and packets are sent out as I intended.
On the receiving side, I'm not so lucky. Linux does not give my receiving socket the multicast packets. It just won't see them, although tcpdump proves that they arrive at the interface. Note that unicast - using the very same sockets - is not a problem at all. I can send and receive them to my heart's content. Not so with multicast.
So I'd like to know what the Linux kernel 'thinks' in that bit between receiving the packet (which it obviously does), and giving it to my process' UDP server socket (which it doesn't do). Any thoughts?

raw socket listener

This is a quick question for linux c programming raw sockets. If I wanted to just listen to any interface with a raw socket, must I actually bind to an ip address or interface to listen to traffic? From what I understand, I feel like I should be able to just call sock(); and then start recvfrom() traffic. Maybe I'm wrong, but I've seen some programs that don't use it.
You are right, the only thing you will need to do is call socket() and then recvfrom(). Nevertheless be aware of the fact that there are some limitations with listening using SOCK_RAW.
If you're not using raw sockets on a "send-and-forget" basis, you will
be interested in reading the reply packet(s) for your raw packet(s).
The decision logic for whether a packet will be delivered to a raw
socket can be enumarated as such:
TCP and UDP packets are never delivered to raw sockets, they are always handled by the kernel protocol stack.
Copies of ICMP packets are delivered to a matching raw socket. For some of the ICMP types (ICMP echo request, ICMP timestamp request,
mask request) the kernel, at the same time, may wish to do some
processing and generate replies.
All IGMP packets are delivered to raw sockets: e.g. OSPF packets.
All other packets destined for protocols that are not processed by a kernel subsystem are delivered to raw sockets.
The fact that you're dealing with a protocol for which reply packets
are delivered to your raw socket does not necessarily mean that you'll
get the reply packet. For this you may also need to consider:
setting the protocol accordingly while creating your socket via socket(2)system call. For instance, if you're sending an ICMP
echo-request packet, and want to receive ICMP echo-reply, you can set
the protocol argument (3rd argument) to IPPROTO_ICMP).
setting the protocol argument in socket(2) to 0, so any protocol number in the received packet header will match.
defining a local address for your socket (via e.g. bind(2)), so if the destination address matches the socket's local address, it'll be
delivered to your application also.
For more details you can read e.g. this.
If you meant to capture the traffic on a interface, you can use libpcap.

Resources