On Windows, `sendto()` ignores its destination parameters when provided with a connection-based socket (currently only SOCK_STREAM), even if they contain invalid data. This patch implements this behavior.
-- v5: ws2_32/tests: Add test for sendto() and recvfrom() on TCP sockets. ntdll/unix: Skip address conversion for SOCK_STREAM sockets in try_send().
From: Ally Sommers dropbear.sh@gmail.com
--- dlls/ntdll/unix/socket.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 4e706323a0a..bc5bc84fdf8 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -985,10 +985,14 @@ static NTSTATUS try_send( int fd, struct async_send_ioctl *async ) union unix_sockaddr unix_addr; struct msghdr hdr; int attempt = 0; + int sock_type; + socklen_t len = sizeof(sock_type); ssize_t ret;
+ getsockopt(fd, SOL_SOCKET, SO_TYPE, &sock_type, &len); + memset( &hdr, 0, sizeof(hdr) ); - if (async->addr) + if (async->addr && sock_type != SOCK_STREAM) { hdr.msg_name = &unix_addr; hdr.msg_namelen = sockaddr_to_unix( async->addr, async->addr_len, &unix_addr );
From: Ally Sommers dropbear.sh@gmail.com
--- dlls/ws2_32/tests/sock.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index cff4acb0b3c..e6ab5065cfe 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -13785,6 +13785,39 @@ static void test_connect_udp(void) closesocket(client); }
+static void test_tcp_sendto_recvfrom(void) +{ + SOCKET client, server = 0; + SOCKADDR_IN addr = { AF_INET, SERVERPORT }; + SOCKADDR_IN bad_addr, bad_addr_copy; + const char serverMsg[] = "ws2_32/TCP socket test"; + char clientBuf[sizeof(serverMsg)] = { 0 }; + int to_len = 0xc0ffee11; + int ret; + + inet_pton(AF_INET, SERVERIP, &addr.sin_addr); + + tcp_socketpair(&client, &server); + + memset(&bad_addr, 0xfe, sizeof(bad_addr)); + memcpy(&bad_addr_copy, &bad_addr, sizeof(bad_addr_copy)); + + ret = sendto(server, serverMsg, sizeof(serverMsg), 0, (SOCKADDR *)&bad_addr, sizeof(bad_addr)); + ok(ret == sizeof(serverMsg), "Incorrect return value from sendto: %d (%d)\n", ret, WSAGetLastError()); + ok(!memcmp(&bad_addr, &bad_addr_copy, sizeof(bad_addr)), "Provided address modified by sendto\n"); + ok(to_len == 0xc0ffee11, "Provided size modified by sendto\n"); + + ret = recvfrom(client, clientBuf, sizeof(clientBuf), 0, (SOCKADDR *)&bad_addr, &to_len); + ok(ret == sizeof(serverMsg), "Incorrect return value from recvfrom: %d (%d)\n", ret, WSAGetLastError()); + ok(!memcmp(&bad_addr, &bad_addr_copy, sizeof(bad_addr)), "Provided address modified by recvfrom\n"); + ok(to_len == 0xc0ffee11, "Provided size modified by recvfrom\n"); + + ok(!memcmp(serverMsg, clientBuf, sizeof(serverMsg)), "Data mismatch over TCP socket\n"); + + closesocket(client); + closesocket(server); +} + START_TEST( sock ) { int i; @@ -13866,6 +13899,7 @@ START_TEST( sock ) test_tcp_reset(); test_icmp(); test_connect_udp(); + test_tcp_sendto_recvfrom();
/* this is an io heavy test, do it at the end so the kernel doesn't start dropping packets */ test_send();