From 4181c0330c921f7a6cb5120a87c3e273cfad2c4c Mon Sep 17 00:00:00 2001 From: Thomas Wagenveld Date: Mon, 2 Aug 2021 19:45:34 +0200 Subject: [PATCH] Ping: Add -s argument to specify the payload size of the ping Change the static buffers to ByteBuffers to deal with the dynamic size of the incoming and outgoing packets. Use sizeof(struct ip) rather than the magic number '20' for the IPv4 header size. Report the size of the reply packet to the console. --- Userland/Utilities/ping.cpp | 73 ++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/Userland/Utilities/ping.cpp b/Userland/Utilities/ping.cpp index 6f841e9b70..24a3d3d646 100644 --- a/Userland/Utilities/ping.cpp +++ b/Userland/Utilities/ping.cpp @@ -5,11 +5,13 @@ */ #include +#include #include #include #include #include #include +#include #include #include #include @@ -27,6 +29,7 @@ static uint32_t total_ms; static int min_ms; static int max_ms; static const char* host; +static int payload_size = -1; static void closing_statistics() { @@ -58,8 +61,14 @@ int main(int argc, char** argv) Core::ArgsParser args_parser; args_parser.add_positional_argument(host, "Host to ping", "host"); args_parser.add_option(count, "Stop after sending specified number of ECHO_REQUEST packets.", "count", 'c', "count"); + args_parser.add_option(payload_size, "Amount of bytes to send as payload in the ECHO_REQUEST packets.", "size", 's', "size"); args_parser.parse(argc, argv); + if (payload_size < 0) { + // Use the default. + payload_size = 32 - sizeof(struct icmphdr); + } + int fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (fd < 0) { perror("socket"); @@ -106,18 +115,6 @@ int main(int argc, char** argv) peer_address.sin_addr.s_addr = *(const in_addr_t*)hostent->h_addr_list[0]; - struct PingPacket { - struct icmphdr header; - char msg[64 - sizeof(struct icmphdr)]; - }; - - struct PongPacket { - // FIXME: IPv4 headers are not actually fixed-size, handle other sizes. - char ip_header[20]; - struct icmphdr header; - char msg[64 - sizeof(struct icmphdr)]; - }; - uint16_t seq = 1; sighandler_t ret = signal(SIGINT, [](int) { @@ -130,24 +127,24 @@ int main(int argc, char** argv) } for (;;) { - PingPacket ping_packet; - memset(&ping_packet, 0, sizeof(PingPacket)); + ByteBuffer ping_packet = ByteBuffer::create_zeroed(sizeof(struct icmphdr) + payload_size); + struct icmphdr* ping_hdr = reinterpret_cast(ping_packet.data()); + ping_hdr->type = ICMP_ECHO; + ping_hdr->code = 0; + ping_hdr->un.echo.id = htons(pid); + ping_hdr->un.echo.sequence = htons(seq++); - ping_packet.header.type = ICMP_ECHO; - ping_packet.header.code = 0; - ping_packet.header.un.echo.id = htons(pid); - ping_packet.header.un.echo.sequence = htons(seq++); + // Fill payload + for (int i = 0; i < payload_size; i++) { + ping_packet[i + sizeof(struct icmphdr)] = i & 0xFF; + } - bool fits = String("Hello there!\n").copy_characters_to_buffer(ping_packet.msg, sizeof(ping_packet.msg)); - // It's a constant string, we can be sure that it fits. - VERIFY(fits); - - ping_packet.header.checksum = internet_checksum(&ping_packet, sizeof(PingPacket)); + ping_hdr->checksum = internet_checksum(ping_packet.data(), ping_packet.size()); struct timeval tv_send; gettimeofday(&tv_send, nullptr); - rc = sendto(fd, &ping_packet, sizeof(PingPacket), 0, (const struct sockaddr*)&peer_address, sizeof(sockaddr_in)); + rc = sendto(fd, ping_packet.data(), ping_packet.size(), 0, (const struct sockaddr*)&peer_address, sizeof(sockaddr_in)); if (rc < 0) { perror("sendto"); return 1; @@ -159,23 +156,25 @@ int main(int argc, char** argv) total_pings++; for (;;) { - PongPacket pong_packet; + // FIXME: IPv4 headers are not actually fixed-size, handle other sizes. + ByteBuffer pong_packet = ByteBuffer::create_uninitialized(sizeof(struct ip) + sizeof(struct icmphdr) + payload_size); + struct icmphdr* pong_hdr = reinterpret_cast(pong_packet.data() + sizeof(struct ip)); socklen_t peer_address_size = sizeof(peer_address); - rc = recvfrom(fd, &pong_packet, sizeof(PongPacket), 0, (struct sockaddr*)&peer_address, &peer_address_size); + rc = recvfrom(fd, pong_packet.data(), pong_packet.size(), 0, (struct sockaddr*)&peer_address, &peer_address_size); if (rc < 0) { if (errno == EAGAIN) { - outln("Request (seq={}) timed out.", ntohs(ping_packet.header.un.echo.sequence)); + outln("Request (seq={}) timed out.", ntohs(ping_hdr->un.echo.sequence)); break; } perror("recvfrom"); return 1; } - if (pong_packet.header.type != ICMP_ECHOREPLY) + if (pong_hdr->type != ICMP_ECHOREPLY) continue; - if (pong_packet.header.code != 0) + if (pong_hdr->code != 0) continue; - if (ntohs(pong_packet.header.un.echo.id) != pid) + if (ntohs(pong_hdr->un.echo.id) != pid) continue; struct timeval tv_receive; @@ -186,7 +185,7 @@ int main(int argc, char** argv) int ms = tv_diff.tv_sec * 1000 + tv_diff.tv_usec / 1000; successful_pings++; - int seq_dif = ntohs(ping_packet.header.un.echo.sequence) - ntohs(pong_packet.header.un.echo.sequence); + int seq_dif = ntohs(ping_hdr->un.echo.sequence) - ntohs(pong_hdr->un.echo.sequence); // Approximation about the timeout of the out of order packet if (seq_dif) @@ -201,15 +200,15 @@ int main(int argc, char** argv) max_ms = ms; char addr_buf[INET_ADDRSTRLEN]; - outln("Pong from {}: id={}, seq={}{}, time={}ms", + outln("Pong from {}: id={}, seq={}{}, time={}ms, size={}", inet_ntop(AF_INET, &peer_address.sin_addr, addr_buf, sizeof(addr_buf)), - ntohs(pong_packet.header.un.echo.id), - ntohs(pong_packet.header.un.echo.sequence), - pong_packet.header.un.echo.sequence != ping_packet.header.un.echo.sequence ? "(!)" : "", - ms); + ntohs(pong_hdr->un.echo.id), + ntohs(pong_hdr->un.echo.sequence), + pong_hdr->un.echo.sequence != ping_hdr->un.echo.sequence ? "(!)" : "", + ms, rc); // If this was a response to an earlier packet, we still need to wait for the current one. - if (pong_packet.header.un.echo.sequence != ping_packet.header.un.echo.sequence) + if (pong_hdr->un.echo.sequence != ping_hdr->un.echo.sequence) continue; break; }