diff --git a/FlyingSocks/Sources/Socket+Darwin.swift b/FlyingSocks/Sources/Socket+Darwin.swift index 2524411..88aca68 100644 --- a/FlyingSocks/Sources/Socket+Darwin.swift +++ b/FlyingSocks/Sources/Socket+Darwin.swift @@ -51,8 +51,11 @@ extension Socket { static let ipproto_ip = Int32(IPPROTO_IP) static let ipproto_ipv6 = Int32(IPPROTO_IPV6) static let ip_pktinfo = Int32(IP_PKTINFO) - static let ipv6_pktinfo = Int32(50) // __APPLE_USE_RFC_2292 - static let ipv6_recvpktinfo = Int32(61) // __APPLE_USE_RFC_2292 + // Swift cannot define __APPLE_USE_RFC_3542 before importing Darwin, so + // the RFC 3542 values from are hardcoded: + // IPV6_PKTINFO = IPV6_3542PKTINFO (46), IPV6_RECVPKTINFO (61). + static let ipv6_pktinfo = Int32(46) // __APPLE_USE_RFC_3542 + static let ipv6_recvpktinfo = Int32(61) // __APPLE_USE_RFC_3542 static func makeAddressINET(port: UInt16) -> Darwin.sockaddr_in { Darwin.sockaddr_in( diff --git a/FlyingSocks/Tests/AsyncSocketTests.swift b/FlyingSocks/Tests/AsyncSocketTests.swift index 1237457..20f82c6 100644 --- a/FlyingSocks/Tests/AsyncSocketTests.swift +++ b/FlyingSocks/Tests/AsyncSocketTests.swift @@ -297,6 +297,33 @@ struct AsyncSocketTests { ) } #endif + + @Test + func receiveMessage_ParsesIPv6PacketInfo() async throws { + // TVT-1131 regression: Socket.ipv6_pktinfo must match the cmsg_type + // the kernel delivers for IPV6_RECVPKTINFO — on Darwin the RFC 3542 + // IPV6_PKTINFO (46), per . Datagram sockets enable + // pktinfo delivery in Socket.init, so a received Message carries the + // parsed interface index and local (destination) address. + let (server, port) = try await AsyncSocket.makeLoopbackDatagram() + + async let received: AsyncSocket.Message = server.receive(atMost: 100) + + let client = try await AsyncSocket.makeLoopbackDatagram().0 + try await client.send(Data("Peas 🫛".utf8), to: sockaddr_in6.loopback(port: port)) + + let message = try await received + #expect(try message.payloadString == "Peas 🫛") + #expect(message.interfaceIndex != nil) + let storage = try #require(message.localAddress).makeStorage() + let sin6 = withUnsafeBytes(of: storage) { $0.load(as: sockaddr_in6.self) } + let loopback = sockaddr_in6.loopback(port: 0).sin6_addr + #expect( + withUnsafeBytes(of: sin6.sin6_addr) { received in + withUnsafeBytes(of: loopback) { received.elementsEqual($0) } + } + ) + } #endif }