diff options
Diffstat (limited to 'Semestr 4/sieci/pracownia1')
-rw-r--r-- | Semestr 4/sieci/pracownia1/traceroute.c | 159 |
1 files changed, 139 insertions, 20 deletions
diff --git a/Semestr 4/sieci/pracownia1/traceroute.c b/Semestr 4/sieci/pracownia1/traceroute.c index 88d233a..9281e4f 100644 --- a/Semestr 4/sieci/pracownia1/traceroute.c +++ b/Semestr 4/sieci/pracownia1/traceroute.c @@ -8,9 +8,14 @@ #include <netinet/ip_icmp.h> #include <assert.h> #include <time.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdbool.h> #define MAX_TTL 30 #define MESSAGES_PER_TTL 3 +#define NO_MESSAGES -1 +#define TOO_FEW_MESSAGES -2137 void print_as_bytes (unsigned char* buff, ssize_t length) { @@ -38,7 +43,7 @@ int create_raw_icmp_socket() { return sockfd; } -uint16_t compute_icmp_checksum (const void *buff, int length) +uint16_t compute_icmp_checksum(const void *buff, int length) { uint32_t sum; const uint16_t* ptr = buff; @@ -49,15 +54,12 @@ uint16_t compute_icmp_checksum (const void *buff, int length) return (uint16_t)(~(sum + (sum >> 16))); } -struct icmp create_icmp_header() { - static uint16_t pid = 0; - static uint16_t seq = 0; - +struct icmp create_icmp_header(uint16_t seq) { struct icmp header; header.icmp_type = ICMP_ECHO; header.icmp_code = 0; - header.icmp_id = ++pid; - header.icmp_seq = ++seq; + header.icmp_id = (uint16_t)getpid(); + header.icmp_seq = seq; header.icmp_cksum = 0; header.icmp_cksum = compute_icmp_checksum( (uint16_t*)&header, sizeof(header)); @@ -66,10 +68,10 @@ struct icmp create_icmp_header() { } void send_icmp_packet(int sockfd, struct sockaddr_in *destination, int ttl) { - struct icmp header = create_icmp_header(); + struct icmp header = create_icmp_header(ttl); setsockopt(sockfd, IPPROTO_IP, IP_TTL, &ttl, sizeof(int)); - printf("%ld %d\n", destination->sin_addr.s_addr, sockfd); + // printf("%u %d\n", destination->sin_addr.s_addr, sockfd); ssize_t bytes_sent = sendto( sockfd, &header, @@ -82,31 +84,146 @@ void send_icmp_packet(int sockfd, struct sockaddr_in *destination, int ttl) { fprintf(stderr, "Error while sending ICMP packet: %s\n", strerror(errno)); exit(EXIT_FAILURE); } - fprintf(stdout, "Bytes sent: %ld\n", bytes_sent); + // fprintf(stdout, "Bytes sent: %ld\n", bytes_sent); } /* Return ip address of the sender of recceived package */ -in_addr_t recv_dontwait(int sockfd) { - struct sockaddr_in sender; - socklen_t sender_len = sizeof(sender); - uint8_t buffer[IP_MAXPACKET]; +ssize_t recv_packet(int sockfd, struct sockaddr_in *sender, uint8_t *buffer) { + socklen_t sender_len = sizeof(*sender); - ssize_t packet_len = recvfrom(sockfd, buffer, IP_MAXPACKET, MSG_DONTWAIT, - (struct sockaddr*)&sender, &sender_len); + ssize_t packet_len = recvfrom(sockfd, buffer, IP_MAXPACKET, 0, + (struct sockaddr*)sender, &sender_len); if (packet_len == -1) { fprintf(stderr, "Error while recieving a packet: %s\n", strerror(errno)); exit(EXIT_FAILURE); } + return packet_len; +} + +void send_icmp_requests(int sockfd, struct sockaddr_in *destination, int ttl, int tries) { + for (int i = 0; i < tries; i++) { + send_icmp_packet(sockfd, destination, ttl); + } +} + +int try_select(int sockfd, struct timeval *tv) { + fd_set descriptors; + FD_ZERO(&descriptors); + FD_SET(sockfd, &descriptors); + return select(sockfd+1, &descriptors, NULL, NULL, tv); +} + +void in_addr_to_string(struct in_addr *sender, char *ip_str) { + inet_ntop(AF_INET, sender, ip_str, sizeof(ip_str)); +} + +void debug_recieved(uint8_t *buffer, struct sockaddr_in *sender, int packet_len) { + char ip_str[20]; + inet_ntop(AF_INET, &(sender->sin_addr), ip_str, sizeof(ip_str)); + + // in_addr_to_string(&(sender->sin_addr), ip_str); + printf("IP packet with ICMP content from: %s\n", ip_str); + struct ip* ip_header = (struct ip*) buffer; + ssize_t ip_header_len = 4 * ip_header->ip_hl; + + printf ("IP header: "); + print_as_bytes (buffer, ip_header_len); + printf("\n"); + + printf ("IP data: "); + print_as_bytes (buffer + ip_header_len, packet_len - ip_header_len); + printf("\n\n"); +} + +void pretty_print_router(int ttl, struct in_addr *senders, float mean_wait_time, int messages_recieved) { + char ip_str[20]; + printf("%d.\t", ttl); + if (messages_recieved == 0) { + printf("*\n"); + } + else { + for (int i = 0; i < messages_recieved; i++) { + bool already_printed = false; + for (int j = 0; j < i; j++) { + if (senders[i].s_addr == senders[j].s_addr) { + already_printed = true; + break; + } + } + if (already_printed) continue; + inet_ntop(AF_INET, senders + i, ip_str, sizeof(ip_str)); + // in_addr_to_string(senders + i, ip_str); + printf("%-15s ", ip_str); + } + if (messages_recieved < MESSAGES_PER_TTL) printf("\t???\n"); + else printf("\t%.2fms\n", mean_wait_time); + } +} + +void get_important_data(uint8_t *buffer, uint8_t *code, uint16_t *id, uint16_t *seq) { + struct ip* ip_header = (struct ip*) buffer; + ssize_t offset = 4 * ip_header->ip_hl; + *code = ((struct icmp *)(buffer + offset))->icmp_type; + if (*code == ICMP_TIMXCEED) { + offset += ICMP_MINLEN; + offset += 4 * ((struct ip *)(buffer + offset))->ip_hl; + *seq = ((struct icmp *)(buffer + offset))->icmp_seq; + *id = ((struct icmp *)(buffer + offset))->icmp_id; + } + else if (*code != ICMP_ECHOREPLY) { + fprintf(stderr, "Something went wrong, recieved ICMP packet with code %d\n.", *code); + exit(EXIT_FAILURE); + } else { + *seq = ((struct icmp *)(buffer + offset))->icmp_seq; + *id = ((struct icmp *)(buffer + offset))->icmp_id; + } +} - return sender.sin_addr.s_addr; +// timeout in milliseconds +float get_replies(int sockfd, long timeout, int ttl, int *messages_recieved, struct in_addr *senders) { + struct sockaddr_in sender; + uint8_t buffer[IP_MAXPACKET]; + int ready; + long mean_wait_time = 0; + struct timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = 0; + *messages_recieved = 0; + + while ((ready = try_select(sockfd, &tv))) { + if (ready < 0) { + fprintf(stderr, "Select error: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + recv_packet(sockfd, &sender, buffer); + uint8_t icmp_code = 0; + uint16_t seq = 0, id = 0; + + get_important_data(buffer, &icmp_code, &id, &seq); + if (seq == ttl) { + senders[(*messages_recieved)++] = sender.sin_addr; + mean_wait_time += timeout * 1000 - tv.tv_usec; + + if (*messages_recieved == MESSAGES_PER_TTL) break; + } + } + // changing from microseconds to miliseconds + return (float)mean_wait_time / 3.0 / 1000.0; } -int traceroute(struct sockaddr_in *destination) { - int sockfd = create_raw_icmp_socket(); +void traceroute(struct sockaddr_in *destination) { + int sockfd = create_raw_icmp_socket(), messages_recieved = 0; + struct in_addr senders[MESSAGES_PER_TTL]; for (int ttl = 1; ttl <= MAX_TTL; ++ttl) { - send_icmp_packet(sockfd, destination, ttl); + send_icmp_requests(sockfd, destination, ttl, MESSAGES_PER_TTL); + float mean_wait_time = get_replies(sockfd, 1000, ttl, &messages_recieved, senders); + pretty_print_router(ttl, senders, mean_wait_time, messages_recieved); + for (int i = 0; i < messages_recieved; i++) { + if (senders[i].s_addr == destination->sin_addr.s_addr) { + return; + } + } } } @@ -118,4 +235,6 @@ int main(int argc, char * argv[]) { struct sockaddr_in destination = get_sockaddr_from_ip(argv[1]); traceroute(&destination); + + return 0; }
\ No newline at end of file |