/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* icmp.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: tomoron +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/04/24 22:49:22 by tomoron #+# #+# */ /* Updated: 2025/06/03 00:40:54 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ #include "includes/ft_ping.h" static void set_packet_data(uint8_t *packet_data) { int i; i = 0; while(i < PACKET_DATA_LENGTH) { packet_data[i] = i; i++; } } uint16_t calc_checksum(void *ptr, size_t len) { uint32_t res; uint16_t *data; data = ptr; res = 0; while (len > 1) { res += *data; data++; len -= 2; } if (len) res += *(uint8_t *)data; while (res >> 16) { res = (res & 0xFFFF) + (res >> 16); } return(~res); } t_icmp_echo prepare_icmp_echo(uint16_t sequence, uint16_t identifier) { t_icmp_echo packet; packet.type = 8; packet.code = 0; packet.identifier = htons(identifier); packet.sequence = htons(sequence); set_packet_data(packet.data); gettimeofday(&packet.time, 0); packet.checksum = 0; packet.checksum = calc_checksum(&packet, sizeof(t_icmp_echo)); return(packet); } t_waitlist *send_icmp(t_settings *set, struct addrinfo *host, uint16_t *seq, struct timeval *last, t_stats *stats) { t_icmp_echo packet; t_waitlist *ret; size_t len; if(timediff(last) < set->interval) return (0); packet = prepare_icmp_echo(*seq, set->id); len = sendto(set->socket, &packet, sizeof(t_icmp_echo), 0, host->ai_addr, host->ai_addrlen); if(len == (size_t)-1) { perror(set->name); set->err = 1; g_stop = 1; } gettimeofday(last, 0); ret = malloc(sizeof(t_waitlist)); if(!ret) return(0); ret->time = *last; ret->seq = *seq; ret->next = 0; stats->sent++; gettimeofday(&set->last_send_time, 0); (*seq)++; return(ret); } char *convert_ip(uint32_t ip) { struct in_addr addr = { .s_addr = ip }; return(inet_ntoa(addr)); } void ttl_exceeded(t_icmp_ip_reply *res,t_settings *settings, size_t len) { char *ip_str; t_icmp_ip_reply *sent; ip_str = convert_ip(res->header.saddr); (void) settings; sent = (void *)res + sizeof(struct iphdr) + 8; if(htons(sent->icmp.identifier) != settings->id) { printf("invalid identifier\n"); return ; } //ICMP: type 8, code 0, size 64, id 0x01cd, seq 0x0000 printf("%zu bytes from %s: Time to live exceeded\n", len, ip_str); printf("IP Hdr Dump:\n"); for (size_t i = 0; i < sizeof(struct iphdr); i += 2) { printf(" %04x", *(uint16_t *)(((void *)(&sent->header)) + i)); } printf("\nVr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n"); printf(" %d %d %02x %04x %04x %01x %04x %02x %02x %02x %s",\ sent->header.version, sent->header.ihl, sent->header.tos,\ htons(sent->header.tot_len), htons(sent->header.id), sent->header.frag_off, sent->header.frag_off,\ sent->header.ttl, sent->header.protocol, htons(sent->header.check),\ convert_ip(sent->header.saddr)); printf(" %s\nICMP: ", convert_ip(sent->header.daddr)); printf("type %d, code %d, size %zu, id 0x%04x, seq 0x%04x\n", sent->icmp.type, sent->icmp.code, sent->header.tot_len - sizeof(struct iphdr), sent->icmp.identifier, sent->icmp.sequence); } void receive_icmp(t_settings *set, t_waitlist **wl, t_stats *stats) { size_t len; t_icmp_ip_reply *res; char buffer[1024]; uint16_t checksum; t_waitlist *elem; len = recvfrom(set->socket, &buffer, 1024, 0, 0, 0); res = (void *)buffer; if(len == (size_t)-1 ) return; if(len < sizeof(struct iphdr) + 8) return; if(res->header.protocol != 1) return ; if(htons(res->header.tot_len) != len) return; if(res->icmp.type == 11) { if(len < (sizeof(struct iphdr) + 8) * 2) return; } else if(res->icmp.type == 0) { if(len < sizeof(t_icmp_ip_reply)) return; if(htons(res->icmp.identifier) != set->id) return; } else return; checksum = res->icmp.checksum; res->icmp.checksum = 0; if(calc_checksum(&res->icmp, len - sizeof(struct iphdr)) != checksum) return ; elem = waitlist_remove(wl, res, res->icmp.type == 11); if(!elem) return; if(res->icmp.type == 0) show_ping_res_line(elem, set, res->icmp.sequence, stats, res->header.ttl); else if (res->icmp.type == 11 && set->verbose) ttl_exceeded(res, set, len); free(elem); }