diff --git a/P8/prueba.c b/P8/prueba.c new file mode 100644 index 0000000000000000000000000000000000000000..0805746b68cb9fee401918eeefa968b1443baa30 --- /dev/null +++ b/P8/prueba.c @@ -0,0 +1,219 @@ +/** + * Practica Tema 8: ICMP-TIMESTAMP + * + * Redondo Calleja, Daniel + * Jimenez Prieto, Roberto + * + */ + +#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 // Tiempo de espera en segundos + +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); + } + + memset(&dest_addr, 0, sizeof(dest_addr)); + dest_addr.sin_family = AF_INET; + dest_addr.sin_port = 0; // Inicializar sin_port + if (inet_pton(AF_INET, ip, &dest_addr.sin_addr) <= 0) { + perror("Error al convertir la dirección IP"); + close(sockfd); + exit(EXIT_FAILURE); + } + + // Asociar socket a la dirección local + 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 asociar el socket a la dirección local"); + close(sockfd); + exit(EXIT_FAILURE); + } + + // Construir el mensaje ICMP + TimeStamp icmp_msg; + crearICMPRequest(&icmp_msg); + + // En modo verbose, imprime los detalles del datagrama enviado + 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)); + } + + // Enviar mensaje ICMP + 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}; + int sel = select(sockfd + 1, &readfds, NULL, NULL, &timeout); + if (sel < 0) { + perror("Error en select"); + close(sockfd); + exit(EXIT_FAILURE); + } else if (sel == 0) { + 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); + } + + // Verificar tipo de respuesta + 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 if (recv_reply.icmpMsg.icmpHdr.type == 3){ + imprimeError(recv_reply.icmpMsg.icmpHdr.type, recv_reply.icmpMsg.icmpHdr.code); + }else { + printf("-> ICMP Datagram Not Processed...\n"); + } + + 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; + icmp_msg->icmpHdr.checksum = checksum(icmp_msg, sizeof(TimeStamp)); +} + +unsigned short checksum(void *b, int len) { + unsigned short *buf = b; + unsigned int sum = 0; + + for (; len > 1; len -= 2) { + sum += *buf++; + } + + if (len == 1) { + sum += *(unsigned char *)buf; + } + + sum = (sum >> 16) + (sum & 0xFFFF); + sum += (sum >> 16); + return ~sum; +} + +// Función para imprimir errores ICMP +void imprimeError(unsigned char type, unsigned char code) { + const char *mensaje = ""; // Variable para almacenar el mensaje a imprimir + + // Determinar el mensaje basado en el tipo y código + if (type == 3) { // Destination Unreachable + if (code == 0) mensaje = "-> Destination Unreachable: Net Unreachable"; + else if (code == 1) mensaje = "-> Destination Unreachable: Host Unreachable"; + else if (code == 2) mensaje = "-> Destination Unreachable: Protocol Unreachable"; + else if (code == 3) mensaje = "-> Destination Unreachable: Port Unreachable"; + else if (code == 4) mensaje = "-> Destination Unreachable: Fragmentation Needed"; + else if (code == 5) mensaje = "-> Destination Unreachable: Source Route Failed"; + else if (code == 6) mensaje = "-> Destination Unreachable: Destination Network Unknown"; + else if (code == 7) mensaje = "-> Destination Unreachable: Destination Host Unknown"; + else if (code == 8) mensaje = "-> Destination Unreachable: Source Host Isolated"; + else if (code == 11) mensaje = "-> Destination Unreachable: Destination Network Unreachable for Type of Service"; + else if (code == 12) mensaje = "-> Destination Unreachable: Destination Host Unreachable for Type of Service"; + else if (code == 13) mensaje = "-> Destination Unreachable: Communication Administratively Prohibited"; + else if (code == 14) mensaje = "-> Destination Unreachable: Host Precedence Violation"; + else if (code == 15) mensaje = "-> Destination Unreachable: Precedence Cutoff in Effect"; + else mensaje = "-> Destination Unreachable: Unknown Code"; + } else if (type == 5) { // Redirect + if (code == 1) mensaje = "-> Redirect: Redirect for Destination Host"; + else if (code == 3) mensaje = "-> Redirect: Redirect for Destination Host Based on Type-of-Service"; + else mensaje = "-> Redirect: Unknown Code"; + } else if (type == 11) { // Time Exceeded + if (code == 0) mensaje = "-> Time Exceeded: Time-to-Live Exceeded in Transit"; + else if (code == 1) mensaje = "-> Time Exceeded: Fragment Reassembly Time Exceeded"; + else mensaje = "-> Time Exceeded: Unknown Code"; + } else if (type == 12) { // Parameter Problem + if (code == 0) mensaje = "-> Parameter Problem: Pointer indicates the error"; + else if (code == 1) mensaje = "-> Parameter Problem: Missing a Required Option"; + else if (code == 2) mensaje = "-> Parameter Problem: Bad Length"; + else mensaje = "-> Parameter Problem: Unknown Code"; + } else { // Otros tipos de error ICMP + mensaje = "-> ICMP Error: "; + } + + // Imprimir el mensaje final + printf("%s (Type %d, Code %d)\n", mensaje, type, code); +} \ No newline at end of file