Skip to content

Conversation

@boris-n
Copy link
Contributor

@boris-n boris-n commented May 24, 2025

Implementation for Socket::set_multicast_if_v4_n (similar to Socket::join_multicast_v4_n) which allows to set interface by index or address (via struct InterfaceIndexOrAddress), for Linux/Android/Fuchsia/FreeBSD/NetBSD. (Other OSes seem to have no support for this.)

@boris-n boris-n force-pushed the multicast-if-by-index branch 3 times, most recently from 940165e to f42637a Compare May 28, 2025 07:25
@boris-n boris-n force-pushed the multicast-if-by-index branch from f42637a to 77eb5c7 Compare June 2, 2025 13:07
@boris-n
Copy link
Contributor Author

boris-n commented Jun 2, 2025

Added feature = "all" as setting multicast interface by index is not supported on Windows and MacOSX.

@boris-n boris-n force-pushed the multicast-if-by-index branch from 77eb5c7 to 159c832 Compare June 2, 2025 13:10
@boris-n boris-n force-pushed the multicast-if-by-index branch from 159c832 to 3fac89f Compare July 31, 2025 18:45
@boris-n boris-n force-pushed the multicast-if-by-index branch from 3fac89f to 817cfb1 Compare September 14, 2025 16:17
@boris-n
Copy link
Contributor Author

boris-n commented Sep 14, 2025

Rebased to current master, waiting for review/approval.

@boris-n boris-n force-pushed the multicast-if-by-index branch from 817cfb1 to 6e7e593 Compare November 29, 2025 12:20
@boris-n
Copy link
Contributor Author

boris-n commented Nov 29, 2025

Rebased to current master (again), waiting for review/approval.

@michaelinoue
Copy link

michaelinoue commented Jan 28, 2026

Any thoughts on expanding this to set both an address and an if index? It seems like we're pinned to using either or in this PR, but we could potentially want both (e.g. sending multicast traffic from a particular address on the interface).

Copy link
Collaborator

@Thomasdezeeuw Thomasdezeeuw left a comment

Choose a reason for hiding this comment

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

I left a comment, but I'm not sure about this pr. I don't use these APIs and currently don't have the time to look into them properly. For this to be merged it would be nice if someone with experience with the options could confirm they work as expected. This also needs a test.

src/socket.rs Outdated
"Interface index out of bounds",
));
}
Ipv4Addr::from_bits(*index)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn't seem right. The enum variant clearly say Index, but we're using an IPv4 address. I think we shouldn't support the index here and recommend to use the Address instead for NetBSD, but I'm not sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The implementation is correct (although I have to admit it is probably confusing). The NetBSD API seems to be a bit "unusual" for setting the multicast interface by index. Let me cite from the NetBSD man page (https://man.netbsd.org/NetBSD-7.0/ip.4):

The IP_MULTICAST_IF option overrides the default for subsequent transmissions from a given socket:
struct in_addr addr;
setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr));
where "addr" is the local IP address of the desired interface [...]. An application may also specify an alternative to the default network interface by index:
struct uint32_t idx = htonl(ifindex);
setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &idx, sizeof(idx));
where "ifindex" is an interface index as returned by if_nametoindex(3).

So, while Linux, FreeBSD, Android and Fuchsia use a special struct mreqn (which has a separate field for the interface index) if they want to set the multicast interface by index, NetBSD uses a struct in_addr to set the address by IP and an uint32_t (in network byte order.) to set the address by interface index. struct in_addr and uint32_t both are 4 bytes in size, so the kernel cannot distinguish the two cases from the size parameter. Looking into the kernel code shows that IP addresses in subnet 0.0.0.0/8 are interpreted as interface index (see https://github.com/NetBSD/src/blob/trunk/sys/netinet/ip_output.c#L1691). This is the reason why I converted the interface to an address and used this one with the setsockopt call.

But I agree, the implementation is probably easier to understand if the code aligns to the examples given in the NetBSD manual page. I provided a modified version which does so.

Copy link
Collaborator

Choose a reason for hiding this comment

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

How about we say that InterfaceIndexOrAddress::Index is not supported on NetBSD (maybe even cfg it out?), and only support the Address variant. In the current implementation both are setting the same option (IP_MULTICAST_IF).

If/when NetBSD supports ip_mreqn we can add support as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But NetBSD has support for setting the multicast interface by index, they documented in the man page that you have to pass it as uint32_t in network byte order (as my code now does).
There is no standardized way for setting the multicast interface by index, and some OSes don't support it. But Linux supports it using struct mreq for IP_MULTICAST_IF, and NetBSD supports it using uint32_t in network byte order for IP_MULTICAST_IF - that's totally fine. So why not support it for NetBSD? Only because NetBSD doesn't do it the Linux way using struct ip_mreqn?
(I agree that the NetBSD way is sub-optimal, the API will not be able to bind to an address in 0.0.0.0/8 address. But that's more an issue with the binding to an address instead of binding to an interface index. And as long as this subnet stays reserved, there is no issue with the NetBSD API.)

@boris-n boris-n force-pushed the multicast-if-by-index branch from 6e7e593 to 086130a Compare February 1, 2026 01:10
@boris-n boris-n force-pushed the multicast-if-by-index branch from 086130a to 2638437 Compare February 1, 2026 01:16
@boris-n
Copy link
Contributor Author

boris-n commented Feb 2, 2026

Any thoughts on expanding this to set both an address and an if index? It seems like we're pinned to using either or in this PR, but we could potentially want both (e.g. sending multicast traffic from a particular address on the interface).

This API is not used to set the source address. Even if you use the version with the address, it is only used to select the interface. See details in https://www.man7.org/linux/man-pages/man7/ip.7.html, section about IP_MULTICAST_IF. If you want to set the source address, you have to bind the socket to it.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants