Skip to content

Instantly share code, notes, and snippets.

@ozett
Forked from PhilipSchmid/multicast-on-linux.md
Created October 11, 2022 15:21
Show Gist options
  • Save ozett/230efd99d932620f52a52601e21e7fd7 to your computer and use it in GitHub Desktop.
Save ozett/230efd99d932620f52a52601e21e7fd7 to your computer and use it in GitHub Desktop.
Testing Multicast Traffic on Linux

Testing Multicast Traffic on Linux

Prerequisites

By default Linux ignores Broadcast and Multicast ICMP messages. That's why you need to enable it first:

sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=0

Join and Test Multicast Traffic

To join any mutlicast address (e.g. 224.10.10.10/24) just add it to your active interface (e.g. eth0) and append the keyword autojoin at the end:

ip addr add 224.10.10.10/24 dev eth0 autojoin

Now you can verify the join:

ip -f inet maddr show dev eth0

Finally to test the Multicast communication, ping to the chosen IP address from another host:

ping 224.10.10.10

You should now get an answer from your Multicast enabled host. That's it.

Change IGMP Version

The Linux Kernel normally uses IGMP version 3 to join Multicast groups. If you would rather use IGMP version 2, just change it via the command down here:

echo "2" > /proc/sys/net/ipv4/conf/eth0/force_igmp_version

Multicast Group Join Inside Docker Container

In order to get the commands above here working inside a Docker container, it must be started with the Linux capability NET_ADMIN:

docker run --rm -it --cap-add NET_ADMIN alpine /bin/sh

Fun fact: GNS3 starts all containers with all Linux capabilities added and in priviledged mode.

@ozett
Copy link
Author

ozett commented Oct 12, 2022

https://unix.stackexchange.com/questions/140384/creating-multicast-join-for-tcpdump-captures

Here is the command line I am using to view traffic:

tcpdump -nnXs 0 -i eth1 udp port 22001 and dst 233.54.12.234
This works fine so long as I have a multicast subscription to that group already established. For example, if I run this in another console:

mdump 233.54.12.234 22001 10.13.252.51
tcpdump will see packets. If mdump is not running, tcpdump sees nothing.

@ozett
Copy link
Author

ozett commented Oct 12, 2022

TL;DR - Pick one:

sudo ip addr add 233.54.12.234/32 dev eth1 autojoin

socat STDIO UDP4-RECV:22001,ip-add-membership=233.54.12.234:eth1 > /dev/null

@ozett
Copy link
Author

ozett commented Oct 12, 2022

At first I was going to say "just use ip maddress add and be done with it". The problem is ip maddress only affects link layer multicast addresses not protocol multicast addresses (man 8 ip-maddress).

That being said using the autojoin flag with the address verb does the trick just nicely.

This raises some subsequent questions though. I assume since you'll be running tcpdump or tshark that you have root permission. In the event that you do not 22001 is a high numbered port and other utilities like socat will also get things done.

Don't take my word for it though. Just to test this out we can generate multicast UDP packets with socat or ncat (generally packaged via nmap/nmap-ncat).

On some number of hosts run one of the following two combinations:

Option 1:

sudo ip addr add 233.54.12.234/32 dev eth1 autojoin
Option 2:

socat -u UDP4-RECV:22001,ip-add-membership=233.54.12.234:eth1 /dev/null &
The first option will require either root, or at least the capability CAP_NET_ADMIN. The second option doesn't require root, but also expects to run in the foreground and thus may be less conducive to scripting (though tracking the child process ID and cleaning it up with a trap in BASH may be just what you're looking for.

Once that's done (but before we go nuts testing our tcpdump/tshark command) make sure that the kernel recognizes the interface having joined the correct IGMP group. If you're feeling super fancy you can go nuts parsing the hex out of /proc/net/igmp, but I'd suggest just running netstat -gn.

Once you've verified that you see the interface subscribed to the correct group fire up your tcpdump command:

tcpdump -nnXs 0 -i eth1 udp port 22001 and dst 233.54.12.234
Alternatively, if you don't want to fully go the route of tcpdump (or stumbled upon this answer and are just curious to see multicast in action) you can use socat command above to join and echo the content to STDOUT by replacing /dev/null with STDOUT:

socat -u UDP4-RECV:22001,ip-add-membership=233.54.12.234:eth1
Then, from another machine use one of the following two options to send some simple test data:

Option 1:

socat STDIO UDP-DATAGRAM:233.54.12.234:22001
Option 2:

ncat -u 233.54.12.234 22001
When you run either of those commands it will then interactively wait for input. Just type some things in, hit enter to send, then CTRL+D when you're done to send an EOF message.

At this point you should have seen an end to end test and with a few commands built the worst, most insecure chat system in the world.

N.B. If you want to leave the multicast group joined using ip addr add ... (option 1), you can do this:

sudo ip addr del 233.54.12.234/32 dev eth1 autojoin

@ozett
Copy link
Author

ozett commented Oct 12, 2022

socat -u UDP4-RECV:3671,reuseaddr,ip-add-membership=224.0.23.12:eth0 STDOUT

@ozett
Copy link
Author

ozett commented Oct 12, 2022

https://unix.stackexchange.com/questions/657353/how-to-check-if-someone-is-streaming-rtp-over-a-specific-multicast-address

In an environment where IP multicast isn't simply flooded to all ports of a dumb switch, using tcpdump alone would likely capture no traffic: the switch snooping IGMP reports and queries (or doing itself queries) seeing there is no need for this multicast traffic on machine B's port would just not send it. This also requires a multicast client that used setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, ...) on its socket.

Install socat and use:

socat -d -d -u udp4-recv:5005,reuseaddr,ip-add-membership=239.0.0.1:192.168.0.21 /dev/null
this will:

join the multicast group 239.0.0.1 on the interface with 192.168.0.21 by sending an initial IGMP membership report, which when processed by an IGMP snooping bridge in presence of a querier will then make the smart switch send traffic to machine B's switch port

Optional reuseaddr here allows to run multiple times the same command (multicast at the system level then just makes each command receive a copy of the single multicast flow).

-d -d makes socat verbose: it will also display the source of the received packets.

Once joined, anything related to 239.0.0.1 can now be captured with tcpdump.

If 192.168.0.20 is sending to 239.0.0.1, the received packets will have 192.168.0.20 as source showing what system sent it.

receive the data and forget it to /dev/null. If the data is a video stream (really on port 5005, not say 5004), replacing /dev/null with - | mpv - would display the video using the mpv command.

When socat is stopped, an IGMP leave message will be sent by the kernel. Depending on switch's settings, it will immediately stop sending this multicast destination to machine B or this will happen within the next minute(s). tcpdump might thus continue to capture traffic, but this won't last.

note:

In an environment where the network is handled by a dumb switch (or a virtual linux bridge where the mcast_querier toggle is not set) then tcpdump would capture the multicast traffic in all cases because the switch is flooding it on all of its ports.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment