From 4ed74564864f1f1c44ced5078c780ba5fda74437 Mon Sep 17 00:00:00 2001 From: Optimoos Date: Mon, 19 Jun 2023 14:59:26 -0400 Subject: [PATCH] Ping: Add TTL config option and value to output This change adds the TTL value of the inbound packet to the output of the userland ping program, bringing it more in line with other common ping utilities. It also adds the (optional) -t option to configure the TTL of the outgoing packet if desired. --- Userland/Utilities/ping.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Userland/Utilities/ping.cpp b/Userland/Utilities/ping.cpp index 3bd086a9215..89cb19e905d 100644 --- a/Userland/Utilities/ping.cpp +++ b/Userland/Utilities/ping.cpp @@ -33,6 +33,7 @@ static int max_ms; static DeprecatedString host; static int payload_size = -1; static bool quiet = false; +static Optional ttl; static timespec interval_timespec { .tv_sec = 1, .tv_nsec = 0 }; // variable part of header can be 0 to 40 bytes // https://datatracker.ietf.org/doc/html/rfc791#section-3.1 @@ -90,6 +91,7 @@ ErrorOr serenity_main(Main::Arguments arguments) }); args_parser.add_option(payload_size, "Amount of bytes to send as payload in the ECHO_REQUEST packets.", "size", 's', "size"); args_parser.add_option(quiet, "Quiet mode. Only display summary when finished.", "quiet", 'q'); + args_parser.add_option(ttl, "Set the TTL (time-to-live) value on the ICMP packets.", nullptr, 't', "ttl"); args_parser.parse(arguments); if (count.has_value() && (count.value() < 1 || count.value() > UINT32_MAX)) { @@ -97,6 +99,11 @@ ErrorOr serenity_main(Main::Arguments arguments) return 1; } + if (ttl.has_value() && (ttl.value() < 1 || ttl.value() > 255)) { + warnln("invalid TTL argument: '{}': out of range: 1 <= value <= 255", ttl.value()); + return 1; + } + if (payload_size < 0) { // Use the default. payload_size = 32 - sizeof(struct icmphdr); @@ -112,6 +119,9 @@ ErrorOr serenity_main(Main::Arguments arguments) }; TRY(Core::System::setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout))); + if (ttl.has_value()) { + TRY(Core::System::setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl.value(), sizeof(ttl.value()))); + } auto* hostent = gethostbyname(host.characters()); if (!hostent) { @@ -170,6 +180,7 @@ ErrorOr serenity_main(Main::Arguments arguments) auto& pong_packet = pong_packet_result.value(); socklen_t peer_address_size = sizeof(peer_address); auto result = Core::System::recvfrom(fd, pong_packet.data(), pong_packet.size(), 0, (struct sockaddr*)&peer_address, &peer_address_size); + uint8_t const pong_ttl = pong_packet[8]; if (result.is_error()) { if (result.error().code() == EAGAIN) { if (!quiet) @@ -220,11 +231,12 @@ ErrorOr serenity_main(Main::Arguments arguments) char addr_buf[INET_ADDRSTRLEN]; if (!quiet) - outln("Pong from {}: id={}, seq={}{}, time={}ms, size={}", + outln("Pong from {}: id={}, seq={}{}, ttl={}, time={}ms, size={}", inet_ntop(AF_INET, &peer_address.sin_addr, addr_buf, sizeof(addr_buf)), ntohs(pong_hdr->un.echo.id), ntohs(pong_hdr->un.echo.sequence), pong_hdr->un.echo.sequence != ping_hdr->un.echo.sequence ? "(!)" : "", + pong_ttl, ms, result.value()); // If this was a response to an earlier packet, we still need to wait for the current one.