Skip to content

net/ipforward: Forbid non-forwardable multicast scopes.#18738

Open
ankohuu wants to merge 1 commit intoapache:masterfrom
ankohuu:fix/non-forwardable-multicast
Open

net/ipforward: Forbid non-forwardable multicast scopes.#18738
ankohuu wants to merge 1 commit intoapache:masterfrom
ankohuu:fix/non-forwardable-multicast

Conversation

@ankohuu
Copy link
Copy Markdown
Contributor

@ankohuu ankohuu commented Apr 15, 2026

Summary

NuttX currently supports forwarding of IP multicast packets. This forwarding is not comparable to multicast-capable switches or routers, which rely on IGMP/MLD snooping or multicast routing protocols. Instead, it performs a simple
flooding mechanism based on locally joined IGMP groups, effectively behaving maybe like a relay.

This PR does not change the existing behavior. It only blocks cases that should not be forwarded under the current model.

  • 224.0.0.0/24 for link-local IPv4 multicast scope RFC 3171 224.0.0.0 - 224.0.0.255 (224.0.0/24) Local Network Control Block
  • IPv6 interface-local and link-local multicast destinations RFC 4291 Interface-Local scope spans only a single interface on a node and is useful only for loopback transmission of multicast.

Impact

IP multicast packets behavior changed in above cases.

Testing

The issue was identified while I try to set up a NAT environment using the NuttX simulator. The test setup consists of a sim instance with two network interfaces, both backed by TAP devices.

Env

os: Linux ankohuu-pb16250 6.17.0-1017-oem #17-Ubuntu SMP PREEMPT_DYNAMIC Fri Mar 27 13:48:03 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux
./tools/configure.sh sim:nsh

Config

.config file
    > CONFIG_BASE_DEFCONFIG="sim:nsh-dirty"
    > CONFIG_SIM_NETDEV=y
    > CONFIG_SIM_NETDEV_TAP=y
    > CONFIG_SIM_NETDEV_MTU=1500
    > CONFIG_SIM_NETDEV_NUMBER=2
    > CONFIG_SIM_NET_HOST_ROUTE=y
    > CONFIG_SCHED_LPWORK=y
    > CONFIG_SCHED_LPNTHREADS=1
    > CONFIG_SCHED_LPWORKPRIORITY=100
    > CONFIG_SCHED_LPWORKSTACKSIZE=2048
    > CONFIG_SCHED_LPWORKSTACKSECTION=""
    > CONFIG_NETDEVICES=y
    > CONFIG_MDIO_BUS=y
    > CONFIG_ARCH_HAVE_NET=y
    > CONFIG_ARCH_HAVE_NETDEV_STATISTICS=y
    > CONFIG_NET_MCASTGROUP=y
    > CONFIG_NET=y
    > CONFIG_NET_DEFAULT_MIN_PORT=4096
    > CONFIG_NET_DEFAULT_MAX_PORT=32000
    > CONFIG_NET_ETH_PKTSIZE=590
    > CONFIG_NET_GUARDSIZE=2
    > CONFIG_NET_LL_GUARDSIZE=14
    > CONFIG_NET_RECV_BUFSIZE=0
    > CONFIG_NET_ETHERNET=y
    > CONFIG_NETDEV_IFINDEX=y
    > CONFIG_NET_IPv4=y
    > CONFIG_NET_IPFORWARD=y
    > CONFIG_NET_IPFORWARD_BROADCAST=y
    > CONFIG_NET_IPFORWARD_NSTRUCT=4
    > CONFIG_NET_IPFORWARD_ALLOC_STRUCT=1
    > CONFIG_NET_NAT=y
    > CONFIG_NET_NAT44=y
    > CONFIG_NET_NAT44_FULL_CONE=y
    > CONFIG_NET_NAT_HASH_BITS=5
    > CONFIG_NET_NAT_TCP_EXPIRE_SEC=86400
    > CONFIG_NET_NAT_UDP_EXPIRE_SEC=240
    > CONFIG_NET_NAT_ICMP_EXPIRE_SEC=60
    > CONFIG_NET_NAT_ICMPv6_EXPIRE_SEC=60
    > CONFIG_NET_NAT_ENTRY_RECLAIM_SEC=3600
    > CONFIG_NET_IPFILTER=y
    > CONFIG_NET_IPTABLES=y
    > CONFIG_NET_PREALLOC_DEVIF_CALLBACKS=16
    > CONFIG_NET_ALLOC_DEVIF_CALLBACKS=0
    > CONFIG_NET_SOCKOPTS=y
    > CONFIG_NET_IPV4_CHECKSUMS=y
    > CONFIG_NET_ICMP=y
    > CONFIG_NET_ICMP_PMTU_ENTRIES=0
    > CONFIG_NET_ICMP_CHECKSUMS=y
    > CONFIG_NET_IGMP=y
    > CONFIG_NET_IGMP_CHECKSUMS=y
    > CONFIG_NET_ARP=y
    > CONFIG_NET_ARPTAB_SIZE=16
    > CONFIG_NET_ARP_MAXAGE=120
    > CONFIG_NET_ARP_MAXAGE_UNREACHABLE=1
    > CONFIG_NET_ARP_SEND=y
    > CONFIG_ARP_SEND_MAXTRIES=5
    > CONFIG_ARP_SEND_DELAYMSEC=20
    > CONFIG_NET_SNOOP_BUFSIZE=4096
    > CONFIG_NET_RECV_PACK=y
    > CONFIG_NET_ROUTE=y
    > CONFIG_ROUTE_IPv4_RAMROUTE=y
    > CONFIG_ROUTE_MAX_IPv4_RAMROUTES=4
    > CONFIG_ROUTE_LONGEST_MATCH=y
    > CONFIG_MM_IOB=y
    > CONFIG_IOB_NBUFFERS=8
    > CONFIG_IOB_BUFSIZE=196
    > CONFIG_IOB_ALIGNMENT=4
    > CONFIG_IOB_SECTION=""
    > CONFIG_IOB_NCHAINS=0
    > CONFIG_IOB_THROTTLE=0
    > CONFIG_NETUTILS_IPTABLES=y
    > CONFIG_NETUTILS_NETINIT=y
    > CONFIG_NETINIT_IPADDR=0x0a000002
    > CONFIG_NETINIT_DRIPADDR=0x0a000001
    > CONFIG_NETINIT_NETMASK=0xffffff00
    > CONFIG_NETUTILS_NETLIB=y
    > CONFIG_NETUTILS_PING=y
    > CONFIG_NETUTILS_PING6=y
    > CONFIG_NSH_NETINIT=y
    > CONFIG_NSH_WGET_BUFF_SIZE=512
    > CONFIG_SYSTEM_IPTABLES=y
    > CONFIG_SYSTEM_IPTABLES_PRIORITY=100
    > CONFIG_SYSTEM_IPTABLES_STACKSIZE=2048
    > CONFIG_SYSTEM_PING=y
    > CONFIG_SYSTEM_PING_PROGNAME="ping"
    > CONFIG_SYSTEM_PING_PRIORITY=100
    > CONFIG_SYSTEM_PING_STACKSIZE=2048
    > CONFIG_SYSTEM_PING6=y
    > CONFIG_SYSTEM_PING6_PROGNAME="ping6"
    > CONFIG_SYSTEM_PING6_PRIORITY=100
    > CONFIG_SYSTEM_PING6_STACKSIZE=2048

Test step

  • Use scapy to inject packets to tap0
    def main() -> None:
    pkt = (
        Ether(src="c2:ad:53:d1:33:d4", dst="01:00:5e:00:00:01")
        / IP(src="10.0.0.1", dst="224.0.0.1", ttl=5)
        / UDP(sport=12345, dport=5000)
        / Raw(b"patch1-linklocal")
    )

    sendp(pkt, iface="tap0", verbose=False)
    print("sent 224.0.0.1 via tap0")


   if __name__ == "__main__":
      main()
  • gdb ./nuttx with breakpoints
  (gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000400cd12b in ipv4_forward_broadcast at ipforward/ipv4_forward.c:623
     breakpoint already hit 1 time
     silent
     printf "ENTER ipv4_forward_broadcast ttl=%u\n", (unsigned int)ipv4->ttl
     continue
2       breakpoint     keep y   0x00000000400cd1ae in ipv4_forward_broadcast at ipforward/ipv4_forward.c:646
     breakpoint already hit 1 time
     silent
     printf "DROP_LINKLOCAL ttl=%u\n", (unsigned int)ipv4->ttl
     continue
3       breakpoint     keep y   0x00000000400cd1ce in ipv4_forward_broadcast at ipforward/ipv4_forward.c:657
     silent
     printf "FOREACH ttl=%u\n", (unsigned int)ipv4->ttl
     continue

Log:

    Linux:
    ~/P/nuttx [fix/non-forwardable-multicast] > sudo ./.venv/bin/python ./verify-linklocal-mcast-send.py
    sent 224.0.0.1 via tap0
    ~/P/nuttx [fix/non-forwardable-multicast] > sudo ./.venv/bin/python ./verify-linklocal-mcast-send.py
    sent 224.0.0.1 via tap0
    ~/P/nuttx [fix/non-forwardable-multicast] > sudo ./.venv/bin/python ./verify-linklocal-mcast-send.py
    sent 224.0.0.1 via tap0
    
    Nuttx:
    NuttShell (NSH) NuttX-12.13.0
    nsh> ifconfig
    eth0    Link encap:Ethernet HWaddr 42:b3:0d:d6:82:81 at RUNNING mtu 1500
            inet addr:10.0.0.2 DRaddr:10.0.0.1 Mask:255.255.255.0
    
    eth1    Link encap:Ethernet HWaddr 42:8a:90:eb:ef:03 at DOWN mtu 1500
            inet addr:0.0.0.0 DRaddr:0.0.0.0 Mask:0.0.0.0
    
    nsh> ENTER ipv4_forward_broadcast ttl=5
    DROP_LINKLOCAL ttl=5
    ENTER ipv4_forward_broadcast ttl=5
    DROP_LINKLOCAL ttl=5
    ENTER ipv4_forward_broadcast ttl=5
    DROP_LINKLOCAL ttl=5

RFC 3171 reserves 224.0.0.0/24 for link-local IPv4 multicast
scope, so packets in this range must not be forwarded by routers,
regardless of the TTL value.

IPv6 also defines multicast scopes that must not be forwarded beyond
the local topology. In particular, interface-local and link-local
multicast destinations must not be routed across interfaces.

Add IPv4/IPv6 scope checks so non-forwardable multicast packets are
rejected before entering the multicast forwarding path.

Signed-off-by: Shunchao Hu <ankohuu@gmail.com>
@ankohuu ankohuu requested a review from jerpelea as a code owner April 15, 2026 07:51
@github-actions github-actions bot added Area: Networking Effects networking subsystem Size: S The size of the change in this PR is small labels Apr 15, 2026
@acassis
Copy link
Copy Markdown
Contributor

acassis commented Apr 15, 2026

@ankohuu very nice! Is this multicast behavior of NuttX a BUG or a limitation? If so, please open an Issue here to map and fix it later

if ((net_ip4addr_conv32(ipv4->destipaddr) &
HTONL(0xffffff00)) == HTONL(0xe0000000))
{
return;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it could be interesting to report a network debug warning here, or, do you think it is not necessary? If not, why not?

Copy link
Copy Markdown
Contributor Author

@ankohuu ankohuu Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think this needs to be added:

Let's don’t report it, just drop it.

@ankohuu
Copy link
Copy Markdown
Contributor Author

ankohuu commented Apr 15, 2026

@ankohuu very nice! Is this multicast behavior of NuttX a BUG or a limitation? If so, please open an Issue here to map and fix it later

Hi acassis,

Overall, I tend to think the current multicast behavior in NuttX is not correct. MC forwarding should not be driven by the groups that the local host itself has joined, but, I would not call the current implementation useless; this is why I described it as behaving more like a relay.

Why I limited this change to the current scope:

  • I did not spend additional time going through more NuttX networking code, and I am not yet sufficiently familiar with it to fully validate whether my understanding of the current behavior is right.
  • I lack the historical and design context to infer why the current implementation exists; it appears intentional rather than accidental.
  • My primary goal this time was to sort out the NAT locks, so this issue is just blocking me.

I can open an issue to put this into the backlog:

  • Could you help @ someone familiar with this area to review whether my understanding of multicast and the current NuttX behavior is correct before I open an issue? We can talk here.
  • It would be useful if someone could provide background on the original design decisions.
  • It would also help to clarify the intended direction: whether NuttX should support a more complete multicast model.

Then I am glad to open a bug to track this properly if still necessary
@acassis @xiaoxiang781216 @anchao @masc2008

Shunchao

@acassis
Copy link
Copy Markdown
Contributor

acassis commented Apr 15, 2026

@ankohuu yes, I think it is a better idea to open an issue and include your point of view.
Maybe @wengzhe could help us, he has a better understanding of network.

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

Labels

Area: Networking Effects networking subsystem Size: S The size of the change in this PR is small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants