diff --git a/.vscode/settings.json b/.vscode/settings.json index 158e92b..3af6741 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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" } } \ No newline at end of file diff --git a/Makefile b/Makefile index 36bef0e..e66d4f1 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ # Project Meta Settings NAME = ft_ping -RELEASE_TYPE = Debug +RELEASE_TYPE = Release CURRENT_DIR = ${CURDIR} # Project Build Output Settings diff --git a/includes/main.h b/includes/main.h index 5d45452..ebac5a3 100644 --- a/includes/main.h +++ b/includes/main.h @@ -1,24 +1,23 @@ #ifndef MAIN_H #define MAIN_H -#include #include -#include #include +#include #include #include -#include +#include +#include +#include #include #include -#include +#include +#include #include -#include -#include -#include -#include -#include #include -#include +#include +#include +#include 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 diff --git a/srcs/main.c b/srcs/main.c index a8fff01..0ef4b99 100644 --- a/srcs/main.c +++ b/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); }