error handling and icmp decode on verbose error

This commit is contained in:
2025-05-16 10:19:08 -04:00
parent fad9f5068b
commit 4465e8bfd0
4 changed files with 106 additions and 28 deletions

View File

@ -1,6 +1,13 @@
{
"C_Cpp.errorSquiggles": "disabled",
"files.associations": {
"ip.h": "c"
"ip.h": "c",
"system_error": "c",
"array": "c",
"compare": "c",
"functional": "c",
"tuple": "c",
"type_traits": "c",
"utility": "c"
}
}

View File

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

View File

@ -1,24 +1,23 @@
#ifndef MAIN_H
#define MAIN_H
#include <stdlib.h>
#include <argp.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <poll.h>
#include <signal.h>
#include <stdbool.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip.h>
#include <poll.h>
#include <time.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
struct arguments {
char* args[1];
@ -31,4 +30,11 @@ struct ping_pkt {
char msg[64 - sizeof(struct icmphdr)];
};
#endif //MAIN_H
struct icmp_code_descr {
int type;
int code;
char* diag;
};
#endif // MAIN_H

View File

@ -71,6 +71,26 @@ volatile unsigned long xmit = 0;
volatile unsigned long recvd = 0;
volatile unsigned long rept = 0;
struct icmp_code_descr error_codes[] = {
{ICMP_DEST_UNREACH, ICMP_NET_UNREACH, "Destination Net Unreachable"},
{ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, "Destination Host Unreachable"},
{ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, "Destination Protocol Unreachable"},
{ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, "Destination Port Unreachable"},
{ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, "Fragmentation needed and DF set"},
{ICMP_DEST_UNREACH, ICMP_SR_FAILED, "Source Route Failed"},
{ICMP_DEST_UNREACH, ICMP_NET_UNKNOWN, "Network Unknown"},
{ICMP_DEST_UNREACH, ICMP_HOST_UNKNOWN, "Host Unknown"},
{ICMP_DEST_UNREACH, ICMP_HOST_ISOLATED, "Host Isolated"},
{ICMP_DEST_UNREACH, ICMP_NET_UNR_TOS, "Destination Network Unreachable At This TOS"},
{ICMP_DEST_UNREACH, ICMP_HOST_UNR_TOS, "Destination Host Unreachable At This TOS"},
{ICMP_REDIRECT, ICMP_REDIR_NET, "Redirect Network"},
{ICMP_REDIRECT, ICMP_REDIR_HOST, "Redirect Host"},
{ICMP_REDIRECT, ICMP_REDIR_NETTOS, "Redirect Type of Service and Network"},
{ICMP_REDIRECT, ICMP_REDIR_HOSTTOS, "Redirect Type of Service and Host"},
{ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, "Time to live exceeded"},
{ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, "Frag reassembly time exceeded"}};
uint16_t calc_checksum(void* b, size_t len) {
unsigned short* buf = b;
unsigned int sum = 0;
@ -142,17 +162,15 @@ double nsqrt(double a, double prec) {
return c;
}
void print_ip_hdr(int verbose, struct ip* ip_header) {
if (verbose) {
printf("IP Hdr dump:\n ");
for (size_t i = 0; i < sizeof(*ip_header); i++) {
printf("%02x", *((unsigned char*)ip_header + i));
if (i % 2) {
printf(" ");
}
void print_ip_hdr(struct ip* ip_header) {
printf("IP Hdr dump:\n ");
for (size_t i = 0; i < sizeof(*ip_header); i++) {
printf("%02x", *((unsigned char*)ip_header + i));
if (i % 2) {
printf(" ");
}
printf("\n");
}
printf("\n");
printf("Vr HL TOS Len ID Flg off TTL Pro cks Src\tDst\tData\n");
printf(" %1x %1x %02x %04x %04x %1x %04x %02x %02x %04x %s %s ", ip_header->ip_v, ip_header->ip_hl,
@ -165,6 +183,23 @@ void print_ip_hdr(int verbose, struct ip* ip_header) {
printf("%02x", *cp++);
}
printf("\n");
cp = (unsigned char*)ip_header + (ip_header->ip_hl << 2) * 2 + sizeof(struct icmphdr);
if (ip_header->ip_p == IPPROTO_TCP) {
printf("TCP: from port %u, to port %u (decimal)\n", (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
} else if (ip_header->ip_p == IPPROTO_UDP) {
printf("UDP: from port %u, to port %u (decimal)\n", (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
} else if (ip_header->ip_p == IPPROTO_ICMP) {
struct icmphdr* icmp_reply = (struct icmphdr*)cp;
printf("ICMP: type %u, code %u, size %u", icmp_reply->type, icmp_reply->code,
ntohs(ip_header->ip_len) - (ip_header->ip_hl << 2));
if (icmp_reply->type == ICMP_ECHOREPLY || icmp_reply->type == ICMP_ECHO) {
printf(", id 0x%04x, seq 0x%04x", icmp_reply->un.echo.id, icmp_reply->un.echo.sequence);
}
printf("\n");
}
}
int main(int argc, char** argv) {
@ -230,6 +265,13 @@ int main(int argc, char** argv) {
exit(1);
}
int bc = 1;
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &bc, sizeof(bc)) < 0) {
dprintf(STDERR_FILENO, "%s: setsockopt() failed: %s\n", argv[0], strerror(errno));
close(sock);
exit(1);
}
fds[0].fd = sock;
fds[0].events = POLLIN;
@ -250,6 +292,8 @@ int main(int argc, char** argv) {
struct sockaddr_in localhost;
inet_pton(AF_INET, "127.0.0.1", &(localhost.sin_addr));
struct sockaddr_in broadcast;
inet_pton(AF_INET, "255.255.255.255", &(broadcast.sin_addr));
while (!stop) {
int ret = poll(fds, 1, timeout);
@ -278,15 +322,33 @@ int main(int argc, char** argv) {
char strip[INET_ADDRSTRLEN] = {0};
inet_ntop(AF_INET, &(ip_header->ip_src.s_addr), strip, INET_ADDRSTRLEN);
struct icmphdr* icmp_reply = (struct icmphdr*)(buf + (ip_header->ip_hl << 2));
if (icmp_reply->type == ICMP_ECHO && ip_header->ip_src.s_addr == localhost.sin_addr.s_addr) {
continue;
} else if (icmp_reply->type != ICMP_ECHOREPLY) {
print_ip_hdr(arguments.verbose, ip_header);
if (icmp_reply->type != ICMP_ECHOREPLY) {
if (icmp_reply->type == ICMP_ECHO && ip_header->ip_src.s_addr == localhost.sin_addr.s_addr) {
continue;
}
if (icmp_reply->type == ICMP_ECHO && ip_header->ip_dst.s_addr == broadcast.sin_addr.s_addr) {
continue;
}
char* str = "";
for (size_t i = 0; i < 17; i++) {
if (error_codes[i].type == icmp_reply->type && error_codes[i].code == icmp_reply->code) {
str = error_codes[i].diag;
break;
}
}
printf("%d bytes from %s: %s\n", ntohs(ip_header->ip_len) - (ip_header->ip_hl << 2), strip, str);
if (arguments.verbose) {
print_ip_hdr(ip_header);
}
if (!stop)
pause();
continue;
}
// if (icmp_reply->code) {}
int old_checksum = icmp_reply->checksum;
icmp_reply->checksum = 0;
@ -332,6 +394,9 @@ int main(int argc, char** argv) {
fflush(stdout);
printf("---- %s ping statistics ----\n", arguments.args[0]);
printf("%zu packets transmitted, %zu packets received, ", xmit, recvd);
if (recvd == 0) {
min = 0;
}
if (rept) {
printf("+%zu duplicates, ", rept);
}