error handling and icmp decode on verbose error
This commit is contained in:
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
@ -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"
|
||||
}
|
||||
}
|
2
Makefile
2
Makefile
@ -2,7 +2,7 @@
|
||||
|
||||
# Project Meta Settings
|
||||
NAME = ft_ping
|
||||
RELEASE_TYPE = Debug
|
||||
RELEASE_TYPE = Release
|
||||
CURRENT_DIR = ${CURDIR}
|
||||
|
||||
# Project Build Output Settings
|
||||
|
@ -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
|
||||
|
95
srcs/main.c
95
srcs/main.c
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user