Fix EINVAL when setting IPv6 multicast membership (#17478)

This commit is contained in:
Kai Tamkun
2025-02-21 18:34:40 -08:00
committed by GitHub
parent 8f7143882e
commit bda1ad192d
3 changed files with 56 additions and 3 deletions

View File

@@ -408,7 +408,7 @@ static int bsd_socket_set_membership6(LIBUS_SOCKET_DESCRIPTOR fd, const struct s
mreq.ipv6mr_interface = iface->sin6_scope_id;
}
int option = drop ? IPV6_LEAVE_GROUP : IPV6_JOIN_GROUP;
return setsockopt(fd, IPPROTO_IP, option, &mreq, sizeof(mreq));
return setsockopt(fd, IPPROTO_IPV6, option, &mreq, sizeof(mreq));
}
int bsd_socket_set_membership(LIBUS_SOCKET_DESCRIPTOR fd, const struct sockaddr_storage *addr, const struct sockaddr_storage *iface, int drop) {

View File

@@ -444,12 +444,12 @@ pub const UDPSocket = struct {
return globalThis.throwInvalidArguments("Expected 1 argument, got {}", .{arguments.len});
}
var addr: std.posix.sockaddr.storage = undefined;
var addr = std.mem.zeroes(std.posix.sockaddr.storage);
if (!parseAddr(this, globalThis, JSC.jsNumber(0), arguments[0], &addr)) {
return globalThis.throwValue(bun.JSC.Maybe(void).errnoSys(@as(i32, @intCast(@intFromEnum(std.posix.E.INVAL))), .setsockopt).?.toJS(globalThis));
}
var interface: std.posix.sockaddr.storage = undefined;
var interface = std.mem.zeroes(std.posix.sockaddr.storage);
const res = if (arguments.len > 1 and parseAddr(this, globalThis, JSC.jsNumber(0), arguments[1], &interface)) blk: {
if (addr.family != interface.family) {

View File

@@ -0,0 +1,53 @@
import { describe, expect, it } from "bun:test";
import * as dgram from "node:dgram";
import { isWindows, isMacOS, isIPv6 } from "harness";
describe.skipIf(!isIPv6())("node:dgram", () => {
it("adds membership successfully (IPv6)", () => {
const socket = makeSocket6();
socket.bind(0, () => {
socket.addMembership("ff01::1", getInterface());
if (!isMacOS) {
// macOS seems to be iffy with automatically choosing an interface.
socket.addMembership("ff02::1");
}
});
});
it("doesn't add membership given invalid inputs (IPv6)", () => {
const { promise, resolve, reject } = Promise.withResolvers();
const socket = makeSocket6();
socket.bind(0, () => {
expect(() => {
// fe00:: is not a valid multicast address
socket.addMembership("fe00::", getInterface());
reject();
}).toThrow();
expect(() => {
socket.addMembership("fe00::");
reject();
}).toThrow();
resolve();
});
return promise;
});
});
function makeSocket6() {
return dgram.createSocket({
type: "udp6",
ipv6Only: true,
});
}
function getInterface() {
if (isWindows) {
return "::%1";
}
if (isMacOS) {
return "::%lo0";
}
return "::%lo";
}