mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-25 19:02:07 -05:00
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.
This commit is contained in:
parent
8b61667924
commit
4181c0330c
1 changed files with 36 additions and 37 deletions
|
@ -5,11 +5,13 @@
|
|||
*/
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/ByteBuffer.h>
|
||||
#include <LibCore/ArgsParser.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
#include <serenity.h>
|
||||
#include <signal.h>
|
||||
|
@ -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<struct icmphdr*>(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<struct icmphdr*>(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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue