From: Martin Tonusoo <martin@tonusoo.xyz>
To: netfilter@vger.kernel.org
Subject: Understanding the network stack internals for multicast packets if there is both a raw socket and local subscriber for IGMP messages
Date: Sat, 13 May 2023 02:32:02 +0300 [thread overview]
Message-ID: <CAGhV4zUhx8OGgLQfofQSPiVuQqeimYysYnWMBOizzVbwhyPj-g@mail.gmail.com> (raw)
Hi.
I was building iptables rules for
igmpproxy(https://github.com/pali/igmpproxy) and noticed that packets
addressed to multicast IPs which the host subscribed to, were sent all
the way up to "filter" table INPUT chain while the rest did not travel
further than "mangle" table PREROUTING chain.
I made a small, proof of concept program which configures socket
identically to igmpproxy:
https://gist.github.com/tonusoo/3c878cad74094a15ca8c338475151fb7 As
seen from the code, its using raw sockets for IGMP messages, but also
subscribes to 224.0.0.2 group on interface named ens4. Example where
the program is executed using strace:
root@mr3:~# strace -f -e socket,setsockopt ./mc_socket
socket(AF_INET, SOCK_RAW, IPPROTO_IGMP) = 3
setsockopt(3, SOL_IP, 0xc8 /* IP_??? */, [1], 4) = 0
setsockopt(3, SOL_IP, 0xca /* IP_??? */,
"\1\0\10\1\0\0\0\0\4\0\0\0\0\0\0\0", 16) = 0
setsockopt(3, SOL_IP, IP_ADD_MEMBERSHIP,
{imr_multiaddr=inet_addr("224.0.0.2"),
imr_interface=inet_addr("10.0.2.1")}, 12) = 0
sleeping for 30s..
+++ exited with 0 +++
root@mr3:~#
While the program is running, the ens4 is subscribed to 224.0.0.2 group:
root@mr3:~# ip maddr sh dev ens4
4: ens4
link 01:00:5e:00:00:01
link 01:00:5e:00:00:02
inet 224.0.0.2
inet 224.0.0.1
inet6 ff02::1
inet6 ff01::1
root@mr3:~#
Now there is another virtual machine named "h5" which is connected to
"mr3" via ens3 interface, i.e hosts are connected like this: mr3[ens4]
<-> [ens3]h5. Both "h5" and "mr3" are running Debian
10(4.19.0-23-amd64). In "h5" I'm running two Scapy commands:
sendp(Ether(src='52:54:00:68:b7:4e',
dst='01:00:5e:00:00:02')/IP(src='192.168.0.100',
dst='224.0.0.2')/IGMP(type=0x16, gaddr='224.0.0.2'), iface='ens3',
verbose=0, count=5)
sendp(Ether(src='52:54:00:68:b7:4e',
dst='01:00:5e:01:02:03')/IP(src='192.168.0.100',
dst='239.1.2.3')/IGMP(type=0x16, gaddr='239.1.2.3'), iface='ens3',
verbose=0, count=5)
The first one is sending five IGMP "Membership Report" messages to
224.0.0.2 via ens3 interface and the second one is sending IGMP
"Membership Report" messages to 239.1.2.3.
In case the "mc_socket" program mentioned above is not running, then
the NIC/driver drops the multicast frames in "mr3" which is expected
behavior. When the "mc_socket" program is running, then packets
addressed to 224.0.0.2 go all the way through "filter" table INPUT
chain towards the application layer. Packets addressed to 239.1.2.3
seem to be sent to raw socket somewhere after the "mangle" table
PREROUTING chain. Iptables counters after executing the two Scapy
commands described earlier when the "mc_socket" was running:
root@mr3:~# iptables -t mangle -L PREROUTING -v -n --line-numbers
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source
destination
1 5 140 LOG all -- * * 0.0.0.0/0
239.1.2.3 LOG flags 0 level 4
2 5 140 LOG all -- * * 0.0.0.0/0
224.0.0.2 LOG flags 0 level 4
root@mr3:~#
root@mr3:~# iptables -t mangle -L INPUT -v -n --line-numbers
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source
destination
1 0 0 LOG all -- * * 0.0.0.0/0
239.1.2.3 LOG flags 0 level 4
2 5 140 LOG all -- * * 0.0.0.0/0
224.0.0.2 LOG flags 0 level 4
root@mr3:~#
root@mr3:~# iptables -t filter -L INPUT -v -n --line-numbers
Chain INPUT (policy ACCEPT 1567 packets, 107K bytes)
num pkts bytes target prot opt in out source
destination
1 0 0 LOG all -- * * 0.0.0.0/0
239.1.2.3 LOG flags 0 level 4
2 5 140 LOG all -- * * 0.0.0.0/0
224.0.0.2 LOG flags 0 level 4
root@mr3:~#
Am I correct, that packets addressed to 224.0.0.2 are sent all the way
through the network stack to application layer because ens4 interface
is configured to 224.0.0.2 group while packets addressed to 239.1.2.3
are snatched much earlier by the program which opened the raw socket?
Where in the kernel source code does this split of paths happen?
PS. I hope it's not off-topic as question is more towards Linux
networking and not specifically about Netfilter.
thanks,
Martin
reply other threads:[~2023-05-12 23:32 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAGhV4zUhx8OGgLQfofQSPiVuQqeimYysYnWMBOizzVbwhyPj-g@mail.gmail.com \
--to=martin@tonusoo.xyz \
--cc=netfilter@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).