How to receive multicast packets hitting NIC without actually sending IGMP request? - linux

I have 2 Ubuntu 16.04 machines "A" and "B" in my local network. "A" periodically sends multicast UDP packet targeted at 225.0.0.37.
On system "B" I can verify through wireshark that those packets are hitting my NIC. I want to write a C program which creates a SOCK_DGRAM socket and listens to these packets without sending IGMP join packet in the network. If I write such a program the kernel doesn't allow these packets to reach my application. They get filtered on IP layer 3 (its my guess).
Is there a way of achieving this? I don't want any IGMP packet leaving my system but still want to capture the UDP traffic. One option that I know works is to use SOCK_RAW, but i want to achieve this from SOCK_DGRAM only.
I know that os keeps igmp subscription entries in /proc/net/igmp and /proc/net/dev_mcast. And these entries are created only if I send an IP_ADD_MEMBERSHIP request from an interface from a program. And these entries get cleared as soon as the program terminates. Maybe there is a way to fool kernel to create this entry.

Related

Multicast packets are not sent if I use an address different from 224.0.0.1

I am using this code to experiment with multicast.
I have wireshark running on another PC in the LAN and I am trying to see the packets sent over the network.
If packets are sent to the IP address 224.0.0.1 they are correctly received, if I send them to the address 239.255.255.250 they are not.
I have this entry in my routing table
224.0.0.0/4 dev eth0.100 src 192.0.0.1
I know 192.0.0.1 looks weird, but it is the correct interface address
Do you know why packets are not being sent?
The PC that you are attempting to capture the multicast traffic most likely has multicast filtering enabled and has not enabled reception of the 239.255.255.250 group.
Any host device that communicates multicast joins the 224.0.0.1 (All Hosts group) so packets sent to that group pass the filter, but not packets sent to 239.255.255.250.
Multicast filtering is usually implemented in the network interface and received frames that don't pass the filter will be dropped in hardware instead of being passed up to the Kernel driver. If the frames are not passed to the Kernel, then Wireshark can not capture them.
You can verify the active multicast groups per interface with netstat. I'm assuming you're on a Linux system since you tagged the question with "Linux"
netstat -g
Multicast groups are joined when a socket enables the IP_ADD_MEMBERSHIP socket option. In order to join the group on your capturing device, you'll need a program that creates a socket and joins the multicast group using the IP_ADD_MEMBERSHIP socket option
To add to Joel Cunningham's answer in the case of switched LAN:
There's nothing listening for multicast on 239.255.255.250, thus no IGMP joins are sent out. thus the switch does not propagate these multicast frames to the port where you have the wireshark(1)-running PC.
Again, 226.0.0.1 is well known and is always joined to by all hosts.

Linux socket UDP server - exchanging messages between 2 servers on 2 machines

I am working on a small linux socket project. The goal is to have multiple servers (ie. 1,2,3,4,5) that listen for send get and ACK packets from each of their respective clients. I am currently attempting to implement a routing table protocol whereby 2 servers (A, B) exchange their routing tables (vectors containing respective clients, server name, and number of hops). The issue I am having is with binding a socket to B's external address from A and vice-versa. From what I have read you do not bind to anything other than a local address except in certain cases. What I am wondering is how do I simply fire off a UDP packet from one server to another knowing the (static) IP address of each server?
What I am wondering is how do I simply fire off a UDP packet from one
server to another knowing the (static) IP address of each server?
The short answer is, you can't. At least on the Internet proper, only unicast is widely supported, which means that in order to send a UDP packet to another machine, you'll need to know its IP address (somehow).
The longer answer is: The first thing you often need to do is discover the target machines' IP addresses. That might be a matter of having the user manually enter a list of IP addresses, or if the target machines are on the same LAN, you can program a mechanism for auto-discovering them by having your program send out a broadcast or multicast UDP query packet. Make sure any instances of your program running on the same LAN receive that packet and respond to it by sending back a response UDP packet (the responses can be sent by by unicast or multicast or broadcast, your choice), and then your query-originating computer can know from the responses it receives which other IP addresses your program is presently also running on.
Note that a lot of computers and network devices run firewalls that reject incoming UDP packets by default, so if you packets don't seem to be getting through that is a likely reason why.

Minimum requirements for custom networking stack to send UDP packets?

(edit: solved -- see below)
This is my situation:
TL-MR3020 -----ethernet----- mbed
OpenWRT C/C++ custom networking stack
192.168.2.1 192.168.2.16
TL-MR3020 is a Linux embedded router
mbed is an ARM microcontroller.
On the network I just want them to exchange messages using UDP packets on port 2225. In particular, TL-MR3020 has to periodically send packets every second to 192.168.2.16:2225, while mbed has to periodically send packets every 50ms to 192.168.2.1:2225.
Everything was good untill I removed the network stack library from mbed (lwIP, not so lightweight for me) and written a new minimal stack.
My new stacks sends 5 gratuitous ARP reply just after the ethernet link gets up, then starts sending and receiving udp packets.
Now TL-MR3020 doesn't receive any UDP packet. In particular, with ifconfig I can see packets coming, but my application can't get them.
Also, if I connect my laptop instead of the TL-MR3020, I can see the UDP packets coming, using Wireshark. There's nothing wrong, except done for my application.
I have a node.js script that has to receive the packets, but it doesn't receive nothing, but if I send UDP packets from local to local, the script receives them.
I think that my application is OK also because neither SOCAT can receive the UDP packets using socat - UDP-LISTEN:2225.
I've already checked on TL-MR3020:
arp table has the correct ip-mac assiciation
destination MAC address matches the incoming interface
destination IP address matches the incoming interface
IP checksum: wireshark says good=false, bad=false
UDP checksum: wireshark says good=false, bad=false
So, I'm asking... what are the minimum requirements for a custom networking stack to send UDP packets?
SOLVED:
You need a good checksum in the IP header.
UDP checksum, my case, can be set to zero.
tcpdump is very helpful (thanks to AndrewMcDonnell)

Networking with Python: No response from IP Phone

I'm an Automation Developer and lately I've taken it upon myself to control an IP Phone on my desk (Cisco 7940).
I have a third party application that can control the IP phone with SCCP (Skinny) packets. Through Wireshark, I see that the application will send 4 unique SCCP packets and then receives a TCP ACK message.
SCCP is not very well known, but it looks like this:
Ethernet( IP( TCP( SCCP( ))))
Using a Python packet builder: Scapy, I've been able to send the same 4 packets to the IP Phone, however I never get the ACK. In my packets, I have correctly set the sequence, port and acknowledge values in the TCP header. The ID field in the IP header is also correct.
The only thing I can imagine wrong is that it takes Python a little more than a full second to send the four packets. Whereas the application takes significantly less time. I've tried raising the priority for the Python shell with no luck.
Does anyone have an idea why I may not be receiving the ACK back?
This website may be helpful in debugging why on your machine you aren't seeing the traffic you expect, and taking steps to modify your environment to produce the desired output.
Normally, the Linux kernel takes care of setting up and sending and
receiving network traffic. It automatically sets appropriate header
values and even knows how to complete a TCP 3 way handshake. Uising
the kernel services in this way is using a "cooked" socket.
Scapy does not use these kernel services. It creates a "raw" socket. The
entire TCP/IP stack of the OS is circumvented. Because of this, Scapy
give us compete control over the traffic. Traffic to and from Scapy
will not be filtered by iptables. Also, we will have to take care of
the TCP 3 way handshake ourselves.
http://www.packetlevel.ch/html/scapy/scapy3way.html

send/receive data through multiple interfaces

I have 2 linux based systems - a client with 2 interfaces (1 LAN, 1 modem) and a server.
I open 2 UDP sockets, and use setsockopt with SO_BINDTODEVICE to bind each socket to it's interface.
Then I send a message from client to server through each of those sockets.
Both of them reach server. Server socket reads them, and sends a reply to each of them.
Then I try to read server's reply on the client.
BUT, there is only 1 reply.
Also if I run tcpdump, I see that both of the replies are received on their relevant interfaces, on the same port that they left. Yet only one of them reaches socket. The other is lost?
The "lost" packet is not random, it's the "non" default one. If my routing table is empty, the modem one is lost. If I add a route to server ip from modem interface, the lost packet will be the lan one.
Yet, they always reach server, always return back, always seen in tcpdump, but 1 never reaches socket. How can that be?
There is an ipv4 network configuration parameter called rp_filter (reversed path validation filter). Basically, if the reply to a packet wouldn't go out the interface this packet came in, then this is a bogus packet and should be ignored. Which is why while I saw the packet on the tcpdump, it never reached socket. Disabling it did the trick.
sysctl -w net.ipv4.conf.all.rp_filter=0
sysctl -w net.ipv4.conf.eth0.rp_filter=0
sysctl -w net.ipv4.conf.ppp0.rp_filter=0

Resources