Debugging multicast reception - c

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?

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.

Which function sends ARP packet to ARPD daemon in Linux kernel?

AFAIK, arpd is used to offload certain jobs and memory footprint from kernel. The arpd process can get packets from two sockets:
notification messages from kernel via NETLINK
regular ARP packets such as ARP_REPLY from the host's neighbors, via a PF_PACKET socket.
My question is, how are ARP packets delivered to a userspace socket? When network stack receives an ARP packet, it passes it to arp_rcv() and arp_process() kernel functions, but I wasn't able to locate any code that sends packet to the PF_PACKET socket that arpd registered. I am sure I missed something here..

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.

Receiving Ethernet frames from an UDP port

I need to listen on multiple UDP ports and process received datagrams as Ethernet frames. I cannot think of any other solution than creating a SOCK_RAW socket to receive ethernet frames, check if what I received is an UDP datagram and then extract the datagram to identify the UDP port.
Is there a better way? Is there some kind of socket that would let me receive UDP datagrams on a specific port and still access the whole Ethernet frame?
I suggest you to use pcap library. It's not hard and it's portable between wide area of systems. You can simply filter and capture what you want.
libpcap and WinPcap provide the packet-capture and filtering engines
of many open source and commercial network tools, including protocol
analyzers (packet sniffers), network monitors, network intrusion
detection systems, traffic-generators and network-testers.
Another suggestions is libcrafter which is a high-level packet creator and decoder. Though it's C++ only.
Not sure if this is supported on your platform, but try:
int s=socket(AF_INET,SOCK_PACKET,htons(ETH_P_ALL));
http://www.tldp.org/HOWTO/Ethernet-HOWTO-2.html

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