Read from UDP multicast raspberry pi - c

I've already started a question here (link) about this project I'm doing, and I keep having lots of problems with this.
In my earlier question I wanted to read from a same machine udp multicast and I find out how to do it, but not with ipmidi.(If you didn't read the previous question linked above, ipmidi is a tool for mac/win which allows me to send midi events through an UDP multicast).
I've been working around with wireshark and managed to see that ipmidi is sending datagrams to the ip 225.0.0.37, port 21928, wich tells me that is, in fact, a multicast.
Then I used this code (the listener) to try to echo the datagrams sent by ipmidi with no success (I changed the multicast ip and the port).
After this I decided to try to run this code from the raspberry pi, since I only wanted it to run in my mac for testing purposes, I went to the real thing.
In my raspi I compiled the code again and gcc claimed that setsockopt() had an invalid argument. perror() was useful enough to tell me that the problem was here:
setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))
So I removed the part where it asks for a multicast address to the kernel and made it a simple listening socket at port 21928, but it still won't work.
I have my mac sending midi through ethernet to the raspi.
Now, the actual questions:
I'm now doubting my multicast, so called, knowledge: if my mac is multicasting ipmidi's datagrams, it means the datagrams are being sended through all the possible places in my mac, right? I mean, the ip 225.0.0.37 means multicast through wifi and ethernet or I have to route it to the network interface of my choice?
Since my raspi is, allegedly, receiving the datagrams through the ethernet, making my program listen at the ipmidi's datagram destination port would be enough or do I have to tell it explicitly 'where' those datagrams came from?
Is there an easier way to make a multicast receiving app, like an api for C/C++? I'm currently using C style sockets, as you could see in the code I linked, but this is not the main purpose for the program I'm doing and I find myself spending lots of time just learning about networking instead of focusing on the real thing.
Sorry for the long question, lots of doubts and I wanted to be in context.
Thanks for the help!

Just listening on the port isn't enough - you need to join the multicast group if you want to see datagrams sent to that group.
The "Invalid Argument" error from your setsockopt() call probably means that your mreq argument was bad. For the multicast address you've given, you should be doing:
struct ip_mreqn mreq;
inet_aton("225.0.0.37", &mreq.imr_multiaddr);
mreq.imr_address.s_addr = htonl(INADDR_ANY);
mreq.imr_ifindex = 0;

So, after some research and trial/error my problem was the raspberry pi being hidden behind my mac.
Since my mac was giving internet to the raspberry pi, the multicast wasn't being caught by the raspi, hence the reason why it failed to join it.
About the setsockopt, I made the same mistake has I had originally in the question: 255 instead of 225 in the multicast ip. Because of this, the options IPPROTO_IP and IP_ADD_MEMBERSHIP were wrong, and the program would block there.
Is working now and I already started to code the midi specification.
Thanks for the help, specially to #caf.

Related

Checking if a UDP message is sent in C

I want to check why a program is not receiving UDP messages. A client program is sending 4 integers every time sample. I have a server program that is using "recvfrom()" to get the UDP messages on a port but the program does not seem to be receiving the messages on the port number and is stuck in the "recvfrom" function. I was wondering if there are debugging techniques I can use to debug this issue?
Thanks!
There are many possibilities, common case could be,
Firewall on your machine or in transit, for example, your another endpoint is behind a firewall that disallow UDP inbound traffic from this address.
Routing, make sure the ping works
Your code bug, make sure loopback address works
To debug, you could install Wireshark to inspect specific interface's traffic.

TFTP UDP header checksum failure

I have a codebase in C that parses network packets, and it seems to work with UDP just fine. Except for (the first packet of) TFTP. Is the Ubuntu tftp client (which is actually the BSD netkit TFTP client) faulty in this respect? I have noticed, for example, that when you send the same file, it always sends the same checksum (even though, over different runs, the source port is different, as one would expect, and the UDP checksum is supposed to incorporate the UDP source port).
Am I making the wrong assumptions? Is TFTP different when it comes to UDP header checksums? I know it's not necessarily a programming question, but it's holding up my programming, that's for sure.
What I hadn't noticed is that virtual machines offload the formulation of packets; my tests ran on virtual machines guests. So the answer is, if you ever have corrupt packets on VM's, consult with this link:
http://www.linuxquestions.org/questions/linux-networking-3/help-needed-disabling-tcp-udp-checksum-offloading-in-debian-880233/
follow up, and try again.

When using PF_PACKET type of socket, what does PACKET_ADD_MEMBERSHIP?

When using a PF_PACKET type of socket with protocol type ETH_P_IP, the man packet documentation talks about a socket option for multicast. The socket option is PACKET_ADD_MEMBERSHIP.
Assuming you use PACKET_ADD_MEMBERSHIP socket option on a PF_PACKET socket correctly, what features and benefits and use cases is this socket option for?
Right now I receive all incoming IP packets so I look at each packet to see if it has the correct IP dst-address and UDP dst-port and I skip over all the other packets. Would using PACKET_ADD_MEMBERSHIP socket option mean I don't need to do my own filter because the kernel or driver would filter for me?
I dug into the linux-kernel source and traced down the code a little bit. I found that the ethernet-mac-address you pass in via setsockopt() is added to a list of ethernet-mac-addresses. And then the list is sent to the network-device hardware to do something... but I can't find any authoritative documentation telling me what happens next.
My educated guess is that the ethernet-mac-address list is used by the hardware to filter at the layer-2 ethernet protocol (i.e. the hardware only accepts packets that have a destination ethernet-address that matches one on the list). If there is some good documentation I would welcome that.
(I'm more familiar with TCP/UDP sockets and so this looks very similar to AF_INET type of socket's IP_ADD_MEMBERSHIP socket option... so I was expecting IGMP reports to be generated which would start multicast traffic from the router... but I found out experimentally that no IGMP reports are generated when you use this socket option.)
Your guess is correct. PACKET_ADD_MEMBERSHIP should add addresses to the NIC's hardware filter. As you've surmised, it's intended to allow you to receive multicasts for a number of different addresses without incurring the load(*) of full promiscuous mode.
(* With modern full duplex ethernet, there's generally not a lot of traffic coming to the NIC that it wouldn't want to receive anyway, unless it's in a virtualized environment.)
Note that there is also a separate PACKET_MR_UNICAST which does not appear in the packet(7) man page but works analogously. I would use the appropriate one (unicast vs multicast) for the type of address you're filtering on, as it's conceivable (though unlikely) that a driver would refuse to put a unicast address into the multicast filtering table.
All that being said, you'll still need to keep your software filtering as backup. There are some older drivers that don't implement MAC filtering at all (particularly for multiple unicast addresses). The core kernel or the driver handles this by simply turning on promiscuous mode if the feature isn't available.
As for the relationship with IP_ADD_MEMBERSHIP, the IP_ADD_MEMBERSHIP code will automatically construct the appropriate multicast MAC address and add it to the interface. See ip_mc_filter_add.

Raw sockets linux

May be the question is a bit stupid, but I'll ask it. I read a lot about raw sockets in network, have seen several examples. So, basically with raw sockets it's possible to build own stack of headers, like stack = IP + TCP/UDP + OWN_HEADER. My question is, is it possible to get some kind of ready frame of first two(IP + TCP/UDP) from the linux kernel and then just append own header to them? The operating system in question is linux and the language is C.
I cannot find any function which can do such a thing, but may be I'm digging in a wrong direction.
I would rely on existing protocols (i.e., UDP for best-effort and TCP for reliable) and encapsulate my own header inside them. In practice, this means embed your own protocol over a standard UDP/TCP connection. This way, you can use existing kernel and user-level tools.
If you want to do the other way around (i.e., UDP/TCP encapsulated in your own header) you have to design/implement your own protocol in the linux kernel, which is quite complicated.
No, that is not possible for raw sockets.
You either sit on top of TCP/UDP, in which case the IP stack takes care of the headers and the operation of the protocol(e.g. in the case of TCP how to slice up your data into segments),
So, if you want to add stuff on top of TCP or UDP, that's what a normal TCP or UDP socket is for.
Or you sit on top of IP, in which case it is your responsibility to craft whatever you want on top of IP - That's what a raw socket is for. Though in this case you can construct the IP header as well, or opt in to have the IP stack generate the IP header too.
I don't think you understand what RAW sockets are for. With RAW sockets (s = socket (AF_INET, SOCK_RAW, IPPROTO_RAW)) you have to build everything above the physical layer yourself.
That means you build the IP header (if you want to build your protocol on top of IP of course), you could do your own thing here with AF_PACKET. And if you want TCP, you build the TCP header yourself, and add it to the IP header. In most cases when you use RAW sockets, this is where you would start building your own protocol in place of TCP or UDP, otherwise why use RAW Sockets in the first place? IF you wanted to build your own ICMP or SCTP implementation for example, you would use RAW Sockets.
If you really want to understand how this works I suggest building your own version of "ping" (ICMP echo request implementation, in other words). Its easy to do and easy to test and will force you to get your hands a little dirty.
The man pages cover this entire topic quite well if you ask me. Start at socket.

How to bind a Raw Socket to a specific port?

I am currently working on a programming assignment. The assignment is to implement a client,network emulator, and server. The client passes packets to a network emulator, and the network emulator passes to the server. Vice-versa applies as well. The prerequisite for the assignment is that I may only use raw sockets. So I will create my own IP and UDP headers. I have tested my packets with wireshark. They are all correct and in the proper format(it reads them properly).
Another requirement is that the emulator, client and server all have specific ports they must be bound to. Now, I do not understand how to bind a raw socket to a specific port. All my raw sockets receive all traffic on the host address they are bound to. According to man pages, and everywhere else on the internet, including "Unix Network Programming" by Richard Stevens, this is how they are supposed to work. My teacher has not responded to any of my emails and I probably will not be able to ask him until Tuesday.I see two options in front of me. First I can use libpcap to filter from a specific device and then output to my raw socket. I feel this is way out of scope for our assignment though. Or I can filter them after I receive them from the socket. This apparently has a lot of overhead because all the packets are being copied/moved through the kernel. At least, that is my understanding(please feel free to correct me if i'm wrong).
So my question is:
Is their an option or something I can set for this? Where the raw socket will bind to a port? Have I missed something obvious?
Thank you for your time.
--
The man page for raw(7) says:
A raw socket can be bound to a specific local address using the bind(2) call. If it isn't bound all packets with the specified IP protocol are received. In addition a RAW socket can be bound to a specific network device using SO_BINDTODEVICE; see socket(7).
Edit: You cannot bind a raw socket to a specific port because "port" is a concept in TCP and UDP, not IP. Look at the header diagrams for those three protocols and it should become obvious: you are working at a lower level, where the concept of port is not known.
I would think you're expected to filter the packets in your software. It sounds like the exercise is to learn what the different components of the IP stack do by recreating a simplified piece of it in user space. Normally in the kernel, the IP code would process all packets, verify the IP headers, reassemble fragments, and check the protocol field. If the protocol field is 17 (udp), then it passes it to the UDP code (every UDP packet). It's up to the UDP code to then validate the UDP header and determine if any applications are interested in them based on the destination port.
I imagine your project is expected to more or less mimic this process. Obviously none of it will be as efficient as doing it in the kernel, but since the assignment is to write (part of) an IP stack in user-space, I'd guess efficiency isn't the point of the exercise.

Resources