18

I want to write a linux shell script which will capture specific multicast traffic. Specific as in, I want to create a pcap file that has all the traffic for one specific multicast group/port.

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.

Is there a standard linux-y way to establish these multicast joins before starting the captures? I could use mdump to establish these joins, but that seems wasteful since mdump will process all that data on the group, bbut I'm just going to throw it away.

Note that because my specific environment, I have been discouraged from putting the interface in to promiscuous mode. It may, in fact, be prohibited.

John Dibling
  • 2,180
  • 7
  • 22
  • 33
  • 1
    Unless you're running a non-standard version of tcpdump, you *are* putting the interface into promiscuous mode - the `-p` flag, in standard versions of tcpdump, turns promiscuous mode *off*, as it's *on* by default. In promiscuous mode, it should see all traffic, including the multicast traffic, regardless of whether you have the subscription established - unless you're on a switched network and it's necessary to have the subscription established to have the switch forward you the traffic. –  Jul 02 '14 at 20:47
  • 2
    @GuyHarris: Thanks for the clarification. I am on a switched network. Without the subscription already established (ie with `mdump` running in another console), `tcpdump` sees nothing. – John Dibling Jul 02 '14 at 22:37
  • And if they don't want you running in promiscuous mode, they probably also don't want you (or won't even *let* you) set up a "mirrored port" on the switch (assuming the switch even supports that) to get copies of all traffic through the switch (or all traffic through particular ports, if that's possible). –  Jul 02 '14 at 22:48
  • So what's wrong with doing this with a script? What matters is whether it gets the job done, not whether somebody considers it "the usual way" - what's "unusual" about the script? –  Jul 02 '14 at 22:49
  • Promiscious mode is disabled because enabling it would, apparently, impact the other VMs on the host. This is undesired. I *can* set up a mirrored port at the switch -- these are 40gb aristas -- but I'm not sure I see your point. – John Dibling Jul 03 '14 at 12:05
  • @GuyHarris: Nothing is wrong with doing it in a script; I never said there was anything wrong with that. What I said was using mdump to establish the joins felt un-standard to me. When I searched for a way to just establish a join, and not process the inbound data in any way (which mdump does), I was surprised not to find an established method. Perhaps `msump` or something like it *is* the established method. But I'd rather not have a process reading and processing all that data if I'm just sending it to `/dev/null` -- that's wasteful. – John Dibling Jul 03 '14 at 12:08
  • I take it back somewhat. Looking back I see how it *appears* that I'm saying doing everything in a script is bad. But that's not what I meant. Question edited. – John Dibling Jul 03 '14 at 12:10
  • Note these are two different things: promiscuous mode disables discarding packets which are received but not addressed to any listening address (including broadcast). joining a multicast address tells your network switches and/or routers to submit packets of the multicast group to your machine. This means: promicious mode without joining the multicast group will not dump the packet because it isn't sent to your network interface (in a well configured network). Normally, joining the group is enough for dumping. – Daniel Alder Oct 21 '14 at 14:38
  • @DanielAlder: Right, and that's what's happening here. I don't get any packets unless I join the multicast. That I understand. What I don't know is how best to join that multicast. – John Dibling Oct 22 '14 at 12:21
  • You can use the standard tool iproute2 on Linux to manage multicast addresses: `ip maddr show eth0` or `man 8 ip-maddress`. However this will only allow you to add or delete link layer addresses to or from a network interface. You would have to calculate the matching link layer address by yourself or write some script for that. I could not find a tool doing this. Maybe see those other questions: - https://stackoverflow.com/q/17988757/462636 - https://superuser.com/q/324824/254939 – LeSpocky Apr 16 '18 at 12:20

1 Answers1

20

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


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
Evgeniy Berezovsky
  • 775
  • 1
  • 7
  • 20
Brian Redbeard
  • 2,961
  • 19
  • 44
  • 3
    Wow, it took 4 years to get an answer! I'm not even doing this anymore, and really have no way to test, but I'll accept nonetheless. – John Dibling Sep 08 '18 at 13:38
  • 2
    Comes in handy just right now! :D Thanks Brian :) – quaylar Oct 07 '19 at 08:43
  • I think the first solution needs a newer `ip` as I am getting `Error: either "local" is duplicate, or "autojoin" is a garbage.` on CentOS 7. Second works. Thanks. – HCSF Sep 21 '20 at 03:44