diff --git a/P8/prueba.c b/P8/prueba.c new file mode 100644 index 0000000000000000000000000000000000000000..e7b30e4fa1fe745e1345fdae3c194a01808122f7 --- /dev/null +++ b/P8/prueba.c @@ -0,0 +1,200 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <sys/time.h> +#include "ip-icmp.h" + +#define ICMP_TIMESTAMP 13 +#define ICMP_TIMESTAMP_REPLY 14 +#define TIMEOUT 5 + +void crearICMPRequest(TimeStamp *icmp_msg); +unsigned short checksum(void *b, int len); +void imprimeError(unsigned char type, unsigned char code); + +int main(int argc, char *argv[]) { + if (argc < 2 || argc > 3) { + fprintf(stderr, "Uso: %s ip [-v]\n", argv[0]); + exit(EXIT_FAILURE); + } + + int verbose = (argc == 3 && strcmp(argv[2], "-v") == 0); + const char *ip = argv[1]; + int sockfd; + struct sockaddr_in dest_addr, local_addr; + + // Crear socket RAW para ICMP + sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + if (sockfd < 0) { + perror("Error al crear el socket"); + exit(EXIT_FAILURE); + } + + // Configurar dirección local y hacer bind() + memset(&local_addr, 0, sizeof(local_addr)); + local_addr.sin_family = AF_INET; + local_addr.sin_addr.s_addr = INADDR_ANY; + local_addr.sin_port = 0; + + if (bind(sockfd, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) { + perror("Error al hacer bind del socket"); + close(sockfd); + exit(EXIT_FAILURE); + } + + // Configurar dirección de destino + memset(&dest_addr, 0, sizeof(dest_addr)); + dest_addr.sin_family = AF_INET; + dest_addr.sin_port = 0; + if (inet_pton(AF_INET, ip, &dest_addr.sin_addr) <= 0) { + perror("Error al convertir la dirección IP"); + close(sockfd); + exit(EXIT_FAILURE); + } + + // Construir el mensaje ICMP + TimeStamp icmp_msg; + crearICMPRequest(&icmp_msg); + + if (verbose) { + printf("-> Type: %d\n", icmp_msg.icmpHdr.type); + printf("-> Code: %d\n", icmp_msg.icmpHdr.code); + printf("-> PID : %d\n", icmp_msg.pid); + printf("-> Seq Numbr: %d\n", ntohs(icmp_msg.sequence)); + printf("-> Originate: %u ms\n", icmp_msg.originate); + printf("-> Receive: 0 ms\n"); + printf("-> Transmit: 0 ms\n"); + printf("-> Tamanyo del Datagrama: %ld bytes\n", sizeof(TimeStamp)); + } + + printf("-> Enviando Datagrama ICMP a Destino con IP: %s\n", ip); + if (sendto(sockfd, &icmp_msg, sizeof(icmp_msg), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) < 0) { + perror("Error al enviar el datagrama"); + close(sockfd); + exit(EXIT_FAILURE); + } + printf("-> Timestamp Request enviado correctamente...\n"); + + // Configurar timeout + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(sockfd, &readfds); + + struct timeval timeout = {TIMEOUT, 0}; + if (select(sockfd + 1, &readfds, NULL, NULL, &timeout) < 0) { + perror("Error en select"); + close(sockfd); + exit(EXIT_FAILURE); + } + + if (!FD_ISSET(sockfd, &readfds)) { + printf("-> Tiempo de espera agotado para %s\n", ip); + close(sockfd); + exit(EXIT_FAILURE); + } + + // Recibir respuesta + TimeStampReply recv_reply; + socklen_t addr_len = sizeof(dest_addr); + if (recvfrom(sockfd, &recv_reply, sizeof(recv_reply), 0, (struct sockaddr *)&dest_addr, &addr_len) < 0) { + perror("Error al recibir el datagrama"); + close(sockfd); + exit(EXIT_FAILURE); + } + + printf("\n-> Timestamp Reply recibido desde %s\n", ip); + if (recv_reply.icmpMsg.icmpHdr.type == ICMP_TIMESTAMP_REPLY && recv_reply.icmpMsg.icmpHdr.code == 0) { + int originate = recv_reply.icmpMsg.originate; + int receive = recv_reply.icmpMsg.receive; + int transmit = recv_reply.icmpMsg.transmit; + + struct timeval end_time; + gettimeofday(&end_time, NULL); + int t4 = (end_time.tv_sec * 1000) + (end_time.tv_usec / 1000); + int rtt = (receive - originate) + (t4 - transmit); + + if (verbose) { + printf("-> Originate: %u ms\n", originate); + printf("-> Receive: %u ms\n", receive); + printf("-> Transmit: %u ms\n", transmit); + printf("-> RTT: %u ms\n", rtt); + printf("-> TTL: %d\n", recv_reply.ipHdr.TTL); + printf("-> Tamanyo del Datagrama: %ld bytes\n", sizeof(TimeStampReply)); + } + + printf("-> Respuesta Correcta (Type %d, Code %d)\n", recv_reply.icmpMsg.icmpHdr.type, recv_reply.icmpMsg.icmpHdr.code); + } else { + imprimeError(recv_reply.icmpMsg.icmpHdr.type, recv_reply.icmpMsg.icmpHdr.code); + } + + close(sockfd); + return EXIT_SUCCESS; +} + +void crearICMPRequest(TimeStamp *icmp_msg) { + memset(icmp_msg, 0, sizeof(TimeStamp)); + icmp_msg->icmpHdr.type = ICMP_TIMESTAMP; + icmp_msg->icmpHdr.code = 0; + icmp_msg->pid = getpid(); + icmp_msg->sequence = htons(0); + + struct timeval start_time; + gettimeofday(&start_time, NULL); + icmp_msg->originate = (start_time.tv_sec * 1000) + (start_time.tv_usec / 1000); + icmp_msg->icmpHdr.checksum = 0; // Inicializar el campo checksum a 0. + icmp_msg->icmpHdr.checksum = checksum(icmp_msg, sizeof(TimeStamp)); +} + +// Función para calcular el checksum +unsigned short checksum(void *b, int len) { + unsigned short *buf = b; + unsigned int sum = 0; // Paso 4: Acumulador inicializado a 0. + + // Paso 2: Calcular el número de palabras de 16 bits. + int half_words = len / 2; + + // Paso 5: Recorrer el datagrama sumando palabras de 16 bits. + while (half_words > 0) { + sum += *buf++; // Sumar la palabra actual al acumulador. + half_words--; // Reducir el contador de palabras. + } + + // Si queda un byte adicional (longitud impar), procesarlo. + if (len % 2 == 1) { + sum += *(unsigned char *)buf; // Sumar el último byte como un short. + } + + // Sumar las partes alta y baja del acumulador (1ª vez). + sum = (sum >> 16) + (sum & 0xFFFF); + + // Sumar nuevamente las partes alta y baja del acumulador (2ª vez). + sum += (sum >> 16); + + // Complemento a uno. + return (unsigned short)(~sum); +} + +void imprimeError(unsigned char type, unsigned char code) { + switch (type) { + case 3: // Destination Unreachable + printf("-> Destination Unreachable: "); + switch (code) { + case 0: printf("Net Unreachable\n"); break; + case 1: printf("Host Unreachable\n"); break; + case 2: printf("Protocol Unreachable\n"); break; + case 3: printf("Port Unreachable\n"); break; + default: printf("Unknown Code\n"); break; + } + break; + case 11: + printf("-> Time Exceeded\n"); + break; + default: + printf("-> ICMP Error: Type %d, Code %d\n", type, code); + break; + } +}