diff --git a/srcs/ft_ping.c b/srcs/ft_ping.c index dfade7a..53f9d4d 100644 --- a/srcs/ft_ping.c +++ b/srcs/ft_ping.c @@ -6,40 +6,154 @@ /* By: tomoron +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/04/26 19:54:25 by tomoron #+# #+# */ -/* Updated: 2025/04/29 01:43:38 by tomoron ### ########.fr */ +/* Updated: 2025/04/30 01:57:10 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ #include "includes/ft_ping.h" -void send_icmp(t_settings set, char *host) +struct addrinfo *resolve_ip(char *host) { - (void)set; - (void)host; - printf("would send to %s\n", host); + struct addrinfo hints, *result; + int s; + struct addrinfo *ret; + + memset(&hints, 0, sizeof(hints)); + ret = 0; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + s = getaddrinfo(host, NULL, &hints, &result); + if (s != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); + return(ret); + } + + ret = result; + if(!ret) + return(ret); + ret->ai_next = 0; + result = result->ai_next; + freeaddrinfo(result); + return(ret); } -void ping_host(t_settings set, char *host) +double timediff(struct timeval *from) { - int i; + struct timeval now; + float diff; + + gettimeofday(&now, 0); + diff = ((double)now.tv_sec - from->tv_sec); + diff += (((double)now.tv_usec / 1000000) - ((double)from->tv_usec / 1000000)); + return(diff); +} - i = 0; - while(i < set.count || set.count == -1) +t_waitlist *send_icmp(t_settings *set, struct addrinfo *host, int seq, struct timeval *last) +{ + t_icmp_echo packet; + t_waitlist *ret; + + if(timediff(last) < set->interval) + return (0); + printf("send packet\n"); + packet = prepare_icmp_echo(seq, set->id); + sendto(set->socket, &packet, sizeof(t_icmp_echo), 0, host->ai_addr, host->ai_addrlen); + gettimeofday(last, 0); + ret = malloc(sizeof(t_waitlist)); + if(!ret) + return(0); + ret->time = *last; + ret->seq = seq; + ret->next = 0; + return(ret); +} + +void waitlist_add(t_waitlist **waitlist, t_waitlist *elem) +{ + t_waitlist *cur; + + cur = *waitlist; + + while(cur && cur->next) + cur = cur->next; + if(cur) + cur->next = elem; + else + *waitlist = elem; +} + +void whitelist_free(t_waitlist *lst) +{ + t_waitlist *tmp; + + while(lst) { - send_icmp(set, host); - usleep(set.interval * 1000 * 1000); - i++; + tmp = lst->next; + free(lst); + lst = tmp; } } -void send_pings(t_settings set) +void receive_icmp(t_settings *set, struct addrinfo *info, t_waitlist **wl) +{ + size_t len; + t_icmp_echo packet; + t_waitlist *tmp; + + len = recvfrom(set->socket, &packet, sizeof(t_icmp_echo), 0, info->ai_addr, &info->ai_addrlen); + if(len == -1 || !len) + return; + tmp = *wl; + while(tmp && tmp->seq != packet.sequence) + tmp = tmp->next; + if(tmp) + { + free(tmp); + } + (void)len; + +} + +int ping_host(t_settings *set, char *host) +{ + uint16_t seq; + struct addrinfo *info; + struct timeval last_sent; + t_waitlist *wl; + t_waitlist *tmp; + + seq = 0; + info = resolve_ip(host); + if(!info) + return(0); + last_sent.tv_sec = 0; + last_sent.tv_usec = 0; + wl = 0; + while(seq < set->count || set->count == -1) + { + tmp = send_icmp(set, info, seq, &last_sent); + if(tmp) + waitlist_add(&wl, tmp); + usleep(1000); + receive_icmp(set, info, &wl); + } + while(wl) + receive_icmp(set, info, &wl); + freeaddrinfo(info); + whitelist_free(wl); + return(1); +} + +void send_pings(t_settings *set) { t_host_list *cur; - cur = set.hosts; + cur = set->hosts; while(cur) { - ping_host(set, cur->host); + if(!ping_host(set, cur->host)) + return; cur = cur->next; } } diff --git a/srcs/icmp.c b/srcs/icmp.c index a054af6..1df8517 100644 --- a/srcs/icmp.c +++ b/srcs/icmp.c @@ -6,7 +6,7 @@ /* By: tomoron +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/04/24 22:49:22 by tomoron #+# #+# */ -/* Updated: 2025/04/25 19:14:34 by tomoron ### ########.fr */ +/* Updated: 2025/04/29 19:09:11 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ #include "includes/ft_ping.h" @@ -43,7 +43,7 @@ static uint16_t calc_checksum(void *ptr, size_t len) res = (res & 0xFFFF) + (res >> 16); } - return(htons(~res)); + return(~res); } t_icmp_echo prepare_icmp_echo(uint16_t sequence, uint16_t identifier) diff --git a/srcs/includes/ft_ping.h b/srcs/includes/ft_ping.h index 0368020..6a37b0a 100644 --- a/srcs/includes/ft_ping.h +++ b/srcs/includes/ft_ping.h @@ -7,9 +7,12 @@ #include #include #include +#include +#include #include #include #include +#include #include @@ -26,6 +29,12 @@ Send ICMP ECHO_REQUEST packets to network hosts.\n\ -f, --flood flood ping (root only)\n\ -?, --help give this help list\n" +typedef struct s_waitlist +{ + struct timeval time; + uint16_t seq; + struct s_waitlist *next; +} t_waitlist; typedef struct s_host_list { @@ -39,10 +48,12 @@ typedef struct s_settings int count; // -c (--count) int timeout; // -w (--timeout) double interval; //-i (--interval) - short no_resolve; //-n (--numeric) + int linger; //-W (--linger) int ttl; // --ttl short setTtl; // is ttl set + int socket; + uint16_t id; short stop; short err; @@ -54,9 +65,9 @@ typedef struct s_icmp_echo uint8_t type; uint8_t code; uint16_t checksum; - uint16_t identifier; - uint16_t sequence; - struct timeval time; + uint16_t identifier; + uint16_t sequence; + struct timeval time; uint8_t data[40]; } t_icmp_echo; @@ -65,6 +76,6 @@ int add_host(t_settings *res, char *host); void free_hosts(t_host_list *list); t_settings parse_args(int argc, char **argv); void show_help(t_settings *set, char *name); -void send_pings(t_settings set); +void send_pings(t_settings *set); #endif diff --git a/srcs/main.c b/srcs/main.c index 58979c9..d62b8e8 100644 --- a/srcs/main.c +++ b/srcs/main.c @@ -1,12 +1,12 @@ /* ************************************************************************** */ /* */ /* ::: :::::::: */ -/* ft_ping.c :+: :+: :+: */ +/* main.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: tomoron +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/04/24 00:03:56 by tomoron #+# #+# */ -/* Updated: 2025/04/26 17:08:50 by tomoron ### ########.fr */ +/* Updated: 2025/04/29 18:39:49 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ @@ -15,18 +15,46 @@ void show_help(t_settings *set, char *name) { set->stop = 1; - write(1, "Usage: ", 7); - write(1, name, strlen(name)); - write(1, HELP_MESSAGE, sizeof(HELP_MESSAGE)); + printf("Usage: %s %s", name, HELP_MESSAGE); } +int init_socket(char *name) +{ + int res; + + res = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + if(res == -1) + { + if(errno == EPERM) + fprintf(stderr, "%s: socket creation permission denied, make sure you are runing as root\n", name); + else + fprintf(stderr, "%s: can't initialize socket\n", name); + return(-1); + } + fcntl(res, F_SETFL, O_NONBLOCK); + return(res); +} + +uint16_t get_id(void) +{ + struct timeval time; + uint16_t res; + + gettimeofday(&time,0); + res = (uint8_t)time.tv_sec; + res |= (uint8_t)time.tv_usec << 8; + return(res); + +} int main(int argc, char **argv) { t_settings settings; settings = parse_args(argc, argv); - if(settings.stop || settings.err) + settings.socket = init_socket(argv[0]); + settings.id = get_id(); + if(settings.stop || settings.err || settings.socket == -1) { free_hosts(settings.hosts); return((settings.err != 0) * 64); @@ -36,7 +64,7 @@ int main(int argc, char **argv) fprintf(stderr, "%s: missing host operand\n", argv[0]); return(64); } - send_pings(settings); + send_pings(&settings); free_hosts(settings.hosts); return(0); } diff --git a/srcs/parsing.c b/srcs/parsing.c index 3ba887d..a51f179 100644 --- a/srcs/parsing.c +++ b/srcs/parsing.c @@ -6,7 +6,7 @@ /* By: tomoron +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/04/26 17:01:53 by tomoron #+# #+# */ -/* Updated: 2025/04/29 02:13:24 by tomoron ### ########.fr */ +/* Updated: 2025/04/30 00:17:50 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ #include "includes/ft_ping.h" @@ -98,6 +98,8 @@ void parse_opt(int *i, t_settings *set, int argc, char **argv) set->count = get_set_int(i, argc, argv, 7, set); else if(!strcmp(argv[*i], "-w") || !strncmp(argv[*i], "--timeout", 9)) set->timeout = get_set_int(i, argc, argv, 9, set); + else if(!strcmp(argv[*i], "-W") || !strncmp(argv[*i], "--linger", 8)) + set->timeout = get_set_int(i, argc, argv, 8, set); else if(!strcmp(argv[*i], "-i") || !strncmp(argv[*i], "--interval", 10)) set->interval = get_set_float(i, argc, argv, 10, set); else if(!strncmp(argv[*i], "--ttl", 5)) @@ -105,8 +107,6 @@ void parse_opt(int *i, t_settings *set, int argc, char **argv) set->ttl = get_set_int(i, argc, argv, 5, set); set->setTtl = 1; } - else if(!strcmp(argv[*i], "-n") || !strcmp(argv[*i], "--numeric")) - set->no_resolve = 1; else { fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[*i]);