This commit is contained in:
2025-04-02 11:05:25 -04:00
parent 7db547d711
commit 566213c178
3 changed files with 76 additions and 21 deletions

View File

@ -2,7 +2,7 @@
# Project Meta Settings # Project Meta Settings
NAME = ft_ping NAME = ft_ping
RELEASE_TYPE = Release RELEASE_TYPE = Debug
CURRENT_DIR = ${CURDIR} CURRENT_DIR = ${CURDIR}
# Project Build Output Settings # Project Build Output Settings

View File

@ -13,6 +13,7 @@
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <netinet/ip_icmp.h> #include <netinet/ip_icmp.h>
#include <netinet/ip.h>
#include <poll.h> #include <poll.h>
#include <time.h> #include <time.h>
#include <sys/time.h> #include <sys/time.h>

View File

@ -1,5 +1,21 @@
#include <main.h> #include <main.h>
// ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
// ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠉⠀⢻⣿⣿⣿⣿⣿⣿⡿⠁⠀⠙⢿⣿⣿
// ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⣾⣿⣿⣿⣿⣿⣿⠇⠀⠀⠀⠈⣿⣿
// ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠿⠛⠛⠛⠛⠿⣿⠀⠀⠀⠀⢀⣿⣿
// ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⣀⣤⡀⠀⠀⠀⠀⣀⡀⠀⠀⠀⢀⠀⢸⣿⣿
// ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣴⣿⣿⠇⠀⠀⢠⣾⣿⣿⣆⠀⠀⠀⠀⣿⣿⣿
// ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢡⣿⣿⣿⠀⠀⢀⣿⣿⣿⣿⣿⠀⠀⠀⢸⣿⣿⣿
// ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠁⢸⣿⡿⠃⠀⠀⢸⣿⣿⣿⣿⠏⠀⠀⠀⡘⣿⣿⣿
// ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀⠀⠈⠀⠈⠭⠀⠈⠛⠿⠛⠋⠀⠀⠀⠀⠠⣿⣿⣿
// ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡑⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿
// ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⠈⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿
// ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⠀⢣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿
// ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⠈⢃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿
// ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿
// ⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿
const char* argp_program_version = "ft_ping 1.0"; const char* argp_program_version = "ft_ping 1.0";
const char* argp_program_bug_address = "<jrathelo@student.42nice.fr>"; const char* argp_program_bug_address = "<jrathelo@student.42nice.fr>";
static char doc[] = "Send ICMP ECHO_REQUEST packets to network hosts.\vMandatory or optional arguments to long options " static char doc[] = "Send ICMP ECHO_REQUEST packets to network hosts.\vMandatory or optional arguments to long options "
@ -54,10 +70,6 @@ struct timespec sendt;
unsigned long xmit = 0; unsigned long xmit = 0;
unsigned long recvd = 0; unsigned long recvd = 0;
double min = 0;
double max = 0;
double avg = 0;
uint16_t calc_checksum(void* b, size_t len) { uint16_t calc_checksum(void* b, size_t len) {
unsigned short* buf = b; unsigned short* buf = b;
unsigned int sum = 0; unsigned int sum = 0;
@ -88,7 +100,7 @@ void send_ping() {
struct timeval tmp_tv; struct timeval tmp_tv;
gettimeofday(&tmp_tv, NULL); gettimeofday(&tmp_tv, NULL);
memcpy(packet.msg, &tmp_tv, sizeof(tmp_tv)); memcpy(packet.msg, &tmp_tv, sizeof(struct timeval));
for (long unsigned i = 0; i < sizeof(packet.msg) - sizeof(tmp_tv); ++i) { for (long unsigned i = 0; i < sizeof(packet.msg) - sizeof(tmp_tv); ++i) {
packet.msg[sizeof(tmp_tv) + i] = (char)i; packet.msg[sizeof(tmp_tv) + i] = (char)i;
} }
@ -108,18 +120,36 @@ void sig_handler(int sig) {
} }
} }
double nabs(double a) { return (a < 0) ? -a : a; }
double nsqrt(double a, double prec) {
double b;
double c;
if (a < 0) {
return 0;
}
if (a < prec) {
return 0;
}
c = a / 2;
do {
b = c;
c = (b + a / b) / 2;
} while (nabs(c - b) > prec);
return c;
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
struct arguments arguments; struct arguments arguments;
int timeout = 3000; int timeout = 3000;
struct timespec recvt; struct timespec recvt;
struct pollfd fds[1]; struct pollfd fds[1];
float min; double min = INT32_MAX;
float max; double max = 0;
float avg; double avg = 0;
double stddev = 0;
min = INT32_MAX;
max = 0;
avg = 0;
arguments.verbose = 0; arguments.verbose = 0;
arguments.ttl = 64; arguments.ttl = 64;
@ -151,20 +181,22 @@ int main(int argc, char** argv) {
fds[0].fd = sock; fds[0].fd = sock;
fds[0].events = POLLIN; fds[0].events = POLLIN;
struct sigaction sig_handle; struct sigaction sig_handle = {0};
sig_handle.sa_handler = sig_handler; sig_handle.sa_handler = sig_handler;
sigaction(SIGINT, &sig_handle, 0); sigaction(SIGINT, &sig_handle, 0);
sigaction(SIGALRM, &sig_handle, 0); sigaction(SIGALRM, &sig_handle, 0);
printf("PING %s (%s): %ld data bytes\n", arguments.args[0], arguments.args[0], 64 - sizeof(struct icmphdr));
send_ping(); send_ping();
while (!stop) { while (!stop) {
int ret = poll(fds, 1, timeout); int ret = poll(fds, 1, timeout);
if (ret > 0) { if (ret > 0) {
if (fds[0].revents & POLLIN) { if (fds[0].revents & POLLIN) {
char buf[100]; char buf[100] = {0};
long int bytes_received = recvfrom(sock, buf, 100, 0, NULL, NULL); long int bytes_received = recvfrom(sock, buf, 100, 0, NULL, NULL);
@ -173,34 +205,56 @@ int main(int argc, char** argv) {
return 1; return 1;
} }
if ((size_t)bytes_received < sizeof(struct ip) + sizeof(struct icmphdr) + 8) {
dprintf(STDERR_FILENO, "packet too short (%ld bytes) from %s\n", bytes_received, arguments.args[0]);
pause();
continue;
}
clock_gettime(CLOCK_MONOTONIC, &recvt); clock_gettime(CLOCK_MONOTONIC, &recvt);
struct ip* ip_header = (struct ip*)buf; struct ip* ip_header = (struct ip*)buf;
struct icmphdr* icmp_reply = (struct icmphdr*)(buf + (ip_header->ip_hl << 2)); struct icmphdr* icmp_reply = (struct icmphdr*)(buf + (ip_header->ip_hl << 2));
int old_checksum = icmp_reply->checksum;
icmp_reply->checksum = 0;
if (old_checksum != calc_checksum(icmp_reply, bytes_received - (ip_header->ip_hl << 2))) {
dprintf(STDERR_FILENO, "checksum mismatch from %s\n", arguments.args[0]);
pause();
continue;
}
icmp_reply->checksum = old_checksum;
float tmp = float tmp =
((recvt.tv_sec * 1000 + recvt.tv_nsec / 1000000) - (sendt.tv_sec * 1000 + sendt.tv_nsec / 1000000)); ((recvt.tv_sec * 1000 + recvt.tv_nsec / 1000000) - (sendt.tv_sec * 1000 + sendt.tv_nsec / 1000000));
tmp += ((float)((recvt.tv_nsec - sendt.tv_nsec) % 1000000) / 1000000.0); tmp += ((float)((recvt.tv_nsec - sendt.tv_nsec) % 1000000) / 1000000.0);
printf("%zd bytes from %s: icmp_seq=%d ttl=%d time=%.3f ms \n", bytes_received, arguments.args[0], printf("%zd bytes from %s: icmp_seq=%d ttl=%d time=%.3f ms \n", bytes_received - sizeof(struct ip),
icmp_reply->un.echo.sequence, ip_header->ip_ttl, tmp); arguments.args[0], icmp_reply->un.echo.sequence + 1, ip_header->ip_ttl, tmp);
min = (((min) < (tmp)) ? (min) : (tmp)); min = (((min) < (tmp)) ? (min) : (tmp));
max = (((max) > (tmp)) ? (max) : (tmp)); max = (((max) > (tmp)) ? (max) : (tmp));
avg += tmp; avg += tmp;
stddev += tmp * tmp;
recvd++; recvd++;
} }
} else if (ret == 0) { } else if (ret == 0) {
printf("No reply received within the timeout period\n"); printf("No reply received within the timeout period\n");
} else {
perror("Poll failed");
} }
// else {
// perror("Poll failed");
// }
pause(); pause();
} }
fflush(stdout);
printf("---- %s ping statistics ----\n", arguments.args[0]); printf("---- %s ping statistics ----\n", arguments.args[0]);
printf("%zu packets transmitted, %zu packets received, %zu%% packet loss\n", xmit, recvd, printf("%zu packets transmitted, %zu packets received, %zu%% packet loss\n", xmit, recvd,
(xmit - recvd) / xmit * 100); (xmit - recvd) / xmit * 100);
printf("round-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%%.3f ms\n", min, max, avg / recvd); avg /= recvd;
stddev = stddev / recvd - avg * avg;
printf("round-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms\n", min, max, avg, nsqrt(stddev, 0.0005));
close(sock); close(sock);
} }