[PATCH 2/4] ws2_32/tests: Test ICMP.
Paul Gofman
wine at gitlab.winehq.org
Tue Jul 5 14:53:17 CDT 2022
From: Paul Gofman <pgofman at codeweavers.com>
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
dlls/ws2_32/tests/sock.c | 150 +++++++++++++++++++++++++++++++++++++++
1 file changed, 150 insertions(+)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index f611fe6ed9d..03677b72080 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -12816,6 +12816,155 @@ static void test_tcp_reset(void)
CloseHandle(overlapped.hEvent);
}
+struct icmp_hdr
+{
+ BYTE type;
+ BYTE code;
+ UINT16 checksum;
+ union
+ {
+ struct
+ {
+ UINT16 id;
+ UINT16 sequence;
+ } echo;
+ } un;
+};
+
+struct ip_hdr
+{
+ BYTE v_hl; /* version << 4 | hdr_len */
+ BYTE tos;
+ UINT16 tot_len;
+ UINT16 id;
+ UINT16 frag_off;
+ BYTE ttl;
+ BYTE protocol;
+ UINT16 checksum;
+ ULONG saddr;
+ ULONG daddr;
+};
+
+/* rfc 1071 checksum */
+static unsigned short chksum(BYTE *data, unsigned int count)
+{
+ unsigned int sum = 0, carry = 0;
+ unsigned short check, s;
+
+ while (count > 1)
+ {
+ s = *(unsigned short *)data;
+ data += 2;
+ sum += carry;
+ sum += s;
+ carry = s > sum;
+ count -= 2;
+ }
+ sum += carry; /* This won't produce another carry */
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ if (count) sum += *data; /* LE-only */
+
+ sum = (sum & 0xffff) + (sum >> 16);
+ /* fold in any carry */
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ check = ~sum;
+ return check;
+}
+
+static void test_icmp(const char *dest_addr)
+{
+ static const unsigned int ping_data = 0xdeadbeef;
+ struct icmp_hdr *icmp_h;
+ BYTE send_buf[sizeof(struct icmp_hdr) + sizeof(ping_data)];
+ UINT16 recv_checksum, checksum;
+ unsigned int reply_data;
+ struct sockaddr_in sa;
+ struct ip_hdr *ip_h;
+ struct in_addr addr;
+ BYTE recv_buf[256];
+ SOCKET s;
+ int ret;
+
+ s = WSASocketA(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, 0);
+ if (s == INVALID_SOCKET)
+ {
+ ret = WSAGetLastError();
+ ok(ret == WSAEACCES, "Expected 10013, received %d\n", ret);
+ skip("SOCK_RAW is not supported\n");
+ return;
+ }
+
+ icmp_h = (struct icmp_hdr *)send_buf;
+ icmp_h->type = ICMP4_ECHO_REQUEST;
+ icmp_h->code = 0;
+ icmp_h->checksum = 0;
+ icmp_h->un.echo.id = 0xbeaf; /* will be overwritten for linux ping socks */
+ icmp_h->un.echo.sequence = 1;
+ *(unsigned int *)(icmp_h + 1) = ping_data;
+ icmp_h->checksum = chksum(send_buf, sizeof(send_buf));
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sin_family = AF_INET;
+ sa.sin_port = 0;
+ sa.sin_addr.s_addr = inet_addr(dest_addr);
+
+ ret = sendto(s, (char *)send_buf, sizeof(send_buf), 0, (struct sockaddr*)&sa, sizeof(sa));
+ ok(ret != SOCKET_ERROR, "got error %d.\n", WSAGetLastError());
+
+ ret = recv(s, (char *)recv_buf, sizeof(struct ip_hdr) + sizeof(send_buf) - 1, 0);
+ ok(ret == -1, "got %d\n", ret);
+ ok(WSAGetLastError() == WSAEMSGSIZE, "got %d\n", WSAGetLastError());
+
+ icmp_h->un.echo.sequence = 2;
+ icmp_h->checksum = 0;
+ icmp_h->checksum = chksum(send_buf, sizeof(send_buf));
+
+ ret = sendto(s, (char *)send_buf, sizeof(send_buf), 0, (struct sockaddr*)&sa, sizeof(sa));
+ ok(ret != SOCKET_ERROR, "got error %d.\n", WSAGetLastError());
+
+ memset(recv_buf, 0xcc, sizeof(recv_buf));
+ ret = recv(s, (char *)recv_buf, sizeof(recv_buf), 0);
+ ok(ret == sizeof(struct ip_hdr) + sizeof(send_buf), "got %d\n", ret);
+
+ ip_h = (struct ip_hdr *)recv_buf;
+ icmp_h = (struct icmp_hdr *)(ip_h + 1);
+ reply_data = *(unsigned int *)(icmp_h + 1);
+
+ ok(ip_h->v_hl == ((4 << 4) | (sizeof(*ip_h) >> 2)), "got v_hl %#x.\n", ip_h->v_hl);
+ ok(ntohs(ip_h->tot_len) == sizeof(struct ip_hdr) + sizeof(send_buf),
+ "got tot_len %#x.\n", ntohs(ip_h->tot_len));
+
+ recv_checksum = ip_h->checksum;
+ ip_h->checksum = 0;
+ checksum = chksum((BYTE *)ip_h, sizeof(*ip_h));
+ /* Checksum is 0 for localhost ping on Windows but not for remote host ping. */
+ ok(recv_checksum == checksum || !recv_checksum, "got checksum %#x, expected %#x.\n", recv_checksum, checksum);
+
+ ok(!ip_h->frag_off, "got id %#x.\n", ip_h->frag_off);
+ addr.s_addr = ip_h->saddr;
+ ok(ip_h->saddr == sa.sin_addr.s_addr, "got saddr %s.\n", inet_ntoa(addr));
+ addr.s_addr = ip_h->daddr;
+ ok(!!ip_h->daddr, "got daddr %s.\n", inet_ntoa(addr));
+
+ ok(ip_h->protocol == 1, "got protocol %#x.\n", ip_h->protocol);
+
+ ok(icmp_h->type == ICMP4_ECHO_REPLY, "got type %#x.\n", icmp_h->type);
+ ok(!icmp_h->code, "got code %#x.\n", icmp_h->code);
+ todo_wine ok(icmp_h->un.echo.id == 0xbeaf, "got echo id %#x.\n", icmp_h->un.echo.id);
+ ok(icmp_h->un.echo.sequence == 2, "got echo sequence %#x.\n", icmp_h->un.echo.sequence);
+
+ recv_checksum = icmp_h->checksum;
+ icmp_h->checksum = 0;
+ checksum = chksum((BYTE *)icmp_h, sizeof(send_buf));
+ ok(recv_checksum == checksum, "got checksum %#x, expected %#x.\n", recv_checksum, checksum);
+
+ ok(reply_data == ping_data, "got reply_data %#x.\n", reply_data);
+
+ closesocket(s);
+}
+
START_TEST( sock )
{
int i;
@@ -12892,6 +13041,7 @@ START_TEST( sock )
test_empty_recv();
test_timeout();
test_tcp_reset();
+ test_icmp("127.0.0.1");
/* this is an io heavy test, do it at the end so the kernel doesn't start dropping packets */
test_send();
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/384
More information about the wine-devel
mailing list