Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions FlyingSocks/Sources/Socket+Darwin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 <netinet6/in6.h> 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(
Expand Down
27 changes: 27 additions & 0 deletions FlyingSocks/Tests/AsyncSocketTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 <netinet6/in6.h>. 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
}

Expand Down
Loading