aboutsummaryrefslogtreecommitdiff
path: root/Semestr 4/sieci/pracownia1
diff options
context:
space:
mode:
Diffstat (limited to 'Semestr 4/sieci/pracownia1')
-rw-r--r--Semestr 4/sieci/pracownia1/traceroute.c159
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