#include const char* argp_program_version = "ft_ping 1.0"; const char* argp_program_bug_address = ""; static char doc[] = "Send ICMP ECHO_REQUEST packets to network hosts.\vMandatory or optional arguments to long options " "are also mandatory or optional for any corresponding short options.\n\nOptions marked with (root " "only) are available only to superuser."; static char args_doc[] = "HOST ..."; #define ARG_TTL 256 static struct argp_option options[] = { {0, 0, 0, 0, "Options valid for all request types:\n", 0}, {"verbose", 'v', 0, 0, "verbose output", 0}, {"ttl", ARG_TTL, "N", 0, "specify N as time-to-live", 0}, {0}, }; static error_t parse_opt(int key, char* arg, struct argp_state* state) { struct arguments* arguments = state->input; switch (key) { case 'v': arguments->verbose = 1; break; case ARG_TTL: arguments->ttl = strtoul(arg, NULL, 10); case ARGP_KEY_ARG: if (state->arg_num >= 2) argp_usage(state); arguments->args[state->arg_num] = arg; break; case ARGP_KEY_END: if (state->arg_num < 1) argp_usage(state); break; default: return ARGP_ERR_UNKNOWN; } return 0; } static struct argp argp = {options, parse_opt, args_doc, doc}; static bool stop = false; int sock = 0; static struct sockaddr_in destination; unsigned long xmit = 0; unsigned long recvd = 0; double min = 0; double max = 0; double avg = 0; uint16_t calc_checksum(void * b, const size_t l) { uint16_t sum = 0; for (int i = 0; i < l; i++) { sum += *((uint16_t*)b + i); } return ~sum; } void send_ping() { struct ping_pkt packet = {0}; packet.hdr.type = ICMP_ECHO; packet.hdr.un.echo.id = getpid(); packet.hdr.un.echo.sequence = xmit++; for (int i = 0; i < sizeof(packet.msg) - 1; ++i) { packet.msg[i] = (char)i; } packet.msg[sizeof(packet.msg) - 1] = '\0'; packet.hdr.checksum = calc_checksum(&packet, sizeof(packet)); sendto(sock, &packet, sizeof(packet), 0, (struct sockaddr*)&destination, sizeof(destination)); alarm(1); } void sig_handler(int sig) { if (sig == SIGINT) { stop = true; } else if (sig == SIGALRM) { send_ping(); } } int main(int argc, char** argv) { struct arguments arguments; arguments.verbose = 0; arguments.ttl = 64; argp_parse(&argp, argc, argv, 0, 0, &arguments); memset(&destination, 0, sizeof(destination)); destination.sin_family = AF_INET; destination.sin_addr.s_addr = inet_addr(arguments.args[0]); if (destination.sin_addr.s_addr == INADDR_NONE) { dprintf(sock, "%s: unknown host\n", argv[0]); exit(1); } destination.sin_port = htons(IPPORT_ECHO); sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (sock < 0) { dprintf(STDERR_FILENO, "%s: socket() failed: %s\n", argv[0], strerror(errno)); exit(1); } if (setsockopt(sock, IPPROTO_IP, IP_TTL, &arguments.ttl, sizeof(arguments.ttl)) < 0) { dprintf(STDERR_FILENO, "%s: setsockopt() failed: %s\n", argv[0], strerror(errno)); close(sock); exit(1); } struct sigaction sig_handle; sig_handle.sa_handler = sig_handler; sigaction(SIGINT, &sig_handle, 0); sigaction(SIGALRM, &sig_handle, 0); alarm(1); while (true) { if (stop) { break; } } printf("---- %s ping statistics ----\n", arguments.args[0]); printf("%zu packets transmitted, %zu packets received, %%zu%% packet loss\n", xmit, recvd /*, (xmit - recv) / xmit * 100*/); // printf("round-trip min/avg/max/stddev = %f/%f/%f/%f ms\n"); close(sock); }