diff --git a/Makefile b/Makefile index d8156fe..30a71dc 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ NAME := ft_ping CC := gcc -CFLAGS := -Wall -Wextra -Werror +CFLAGS := -Wall -Wextra -Werror -g LD := $(CC) LDFLAGS := diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..4127d84 --- /dev/null +++ b/src/config.c @@ -0,0 +1,13 @@ +#include "./config.h" + +#include + +void set_default_config(struct config *conf) +{ + conf->count = 5; + conf->flood = false; + conf->interval = 1; + conf->quiet = false; + conf->time_to_live = 54; + conf->verbose = false; +} \ No newline at end of file diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..14993ea --- /dev/null +++ b/src/config.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +struct config { + char *host; + bool flood; + uint64_t timeout; + bool quiet; + uint64_t count; + uint64_t interval; + uint64_t time_to_live; + bool verbose; +}; + +void set_default_config(struct config *conf); \ No newline at end of file diff --git a/src/main.c b/src/main.c index 058ce8b..2d3e6b7 100644 --- a/src/main.c +++ b/src/main.c @@ -1,9 +1,148 @@ +#include "config.h" +#include "parsing.h" +#include +#include +#include +#include +#include +#include #include +#include +#include +#include + +bool loop = true; + +static void signal_handler(int code) +{ + (void)code; + loop = false; +} + +int init_socket(const struct config *conf) +{ + int sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + if (sock_fd == -1) + { + dprintf(2, "ft_ping: open socket failed maybe missing root\n"); + return -1; + } + + struct timeval timeout; + timeout.tv_sec = conf->timeout; + timeout.tv_usec = 0; + + if (setsockopt (sock_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, + sizeof timeout) < 0) + { + close(sock_fd); + dprintf(2, "ft_ping: set socket options failed\n"); + return -1; + } + + if (setsockopt (sock_fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, + sizeof timeout) < 0) + { + close(sock_fd); + dprintf(2, "ft_ping: set socket options failed\n"); + return -1; + } + + return sock_fd; +} + +uint16_t checksum(const uint16_t *data, int len) +{ + uint32_t sum = 0; + int i = 0; + + while (len > 1) + { + sum += data[i++]; + len -= 2; + } + if (len == 1) + sum += ((uint8_t *)data)[i]; + + while (sum >> 16) + sum = (sum & 0xFFFF) + (sum >> 16); + return (~sum); +} + +int send_packet(int sock_fd, const char* host, uint64_t seq, const struct config *conf) +{ + (void) conf; + struct sockaddr_in addr; + inet_aton(host, &addr.sin_addr); + + struct icmphdr icmp_hdr; + memset(&icmp_hdr, 0, sizeof(icmp_hdr)); + icmp_hdr.type = ICMP_ECHO; + icmp_hdr.un.echo.id = getpid(); + icmp_hdr.un.echo.sequence = seq; + icmp_hdr.checksum = checksum((uint16_t*)&icmp_hdr, sizeof(icmp_hdr)); + + if (sendto(sock_fd, &icmp_hdr, sizeof(icmp_hdr), 0, (struct sockaddr*)&addr, sizeof(addr)) == -1) + { + dprintf(2, "ft_printf: failed to send packet\n"); + return 1; + } + return 0; +} + +int recv_packet(int sock_fd, const char *host, uint64_t seq, const struct config *conf) +{ + (void) conf; + (void) host; + char buf[128]; + struct sockaddr_in addr; + + socklen_t len = sizeof(addr); + + int n = recvfrom(sock_fd, buf, sizeof(buf), 0, + (struct sockaddr *)&addr, &len); + if (n == -1) + return 1; + (void) seq; + return 0; +} int main(int ac, char **av) { (void)ac; - (void)av; - printf("PING TA MERE\n"); - return 1; + + signal(SIGINT, signal_handler); + + struct config conf; + set_default_config(&conf); + const char *host = parsing((const char * const *) av, &conf); + if (host == NULL) + return 1; + + const int sock_fd = init_socket(&conf); + if (sock_fd == -1) + return 2; + + static uint64_t seq = 1; + while (loop) + { + if (send_packet(sock_fd, host, seq, &conf)) + { + close(sock_fd); + return 1; + }; + if (recv_packet(sock_fd, host, seq, &conf)) + { + close(sock_fd); + return 1; + } + seq++; + sleep(conf.interval); + } + + printf("PING TA %s\n", host); + + close(sock_fd); + + return 0; } \ No newline at end of file diff --git a/src/parsing.c b/src/parsing.c new file mode 100644 index 0000000..ff6ea0e --- /dev/null +++ b/src/parsing.c @@ -0,0 +1,74 @@ +#include "config.h" + +#include +#include +#include +#include +#include + +static int parse_int (const char *arg, uint64_t* ptr) +{ + *ptr = 0; + for (uint64_t i = 0; arg[i] != '\0'; i++) + { + char c = arg[i]; + if (!isdigit(c)) + { + dprintf(2, "ft_ping: %s: is not a valid number\n", arg); + return 1; + } + *ptr += *ptr * 10 + c - '0'; + } + return 0; +} + +static int parse_count(const char *arg, struct config *conf) +{ + if (arg == NULL) + { + dprintf(2, "ft_ping: -c must be follow by the number of count\n"); + return 1; + } + return parse_int(arg, &conf->count); +} + +static int parse_interval(const char *arg, struct config *conf) +{ + if (arg == NULL) + { + dprintf(2, "ft_ping: -i must be follow by the number of interval\n"); + return 1; + } + return parse_int(arg, &conf->interval); +} + +const char *parsing(const char * const *args, struct config *conf) +{ + const char *arg; + const char *host = NULL; + + for (uint64_t i = 1; args[i] != NULL; i++) + { + arg = args[i]; + if (strcmp(arg, "-v") == 0) + conf->verbose = true; + else if (strcmp(arg, "-q") == 0) + conf->quiet = true; + else if (strcmp(arg, "-c") == 0) + { + if (parse_count(args[++i], conf)) + return NULL; + } + else if (strcmp(arg, "-i") == 0) + { + if (parse_interval(args[++i], conf)) + return NULL; + } + else { + host = arg; + } + } + if (host == NULL) + dprintf(2, "ft_ping: destination address is missing\n"); + return host; +} \ No newline at end of file diff --git a/src/parsing.h b/src/parsing.h new file mode 100644 index 0000000..a7f5011 --- /dev/null +++ b/src/parsing.h @@ -0,0 +1,3 @@ +#pragma once + +const char *parsing(const char * const *args, struct config *conf); \ No newline at end of file