From 7ce0ea07402f8399dded0a990ef23b905b80ed63 Mon Sep 17 00:00:00 2001 From: danredo <daniel.redcal06@gmail.com> Date: Thu, 12 Dec 2024 20:57:45 +0000 Subject: [PATCH] Upload New File --- P8/icmp3.c | 283 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 P8/icmp3.c diff --git a/P8/icmp3.c b/P8/icmp3.c new file mode 100644 index 0000000..9735c2d --- /dev/null +++ b/P8/icmp3.c @@ -0,0 +1,283 @@ +/** + * Practica Tema 8: ICMP-TIMESTAMP + * + * Mata, David + * + * + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/ip.h> // Define sockaddr_in +#include <errno.h> // Para usar errno y perror() +#include <unistd.h> +#include <sys/time.h> +#include "ip-icmp.h" + +#define tiempo_max 5 + +// Funcion para calcular el checksum +unsigned short checksum(TimeStamp *ts) +{ + unsigned int acumulador = 0; + unsigned short *puntero = (unsigned short *)ts; + int i; + int len = sizeof(TimeStamp) / 2; + + // Inicializamos el checksum a 0 + ts->icmpHdr.checksum = 0; + + // Calculamos el checksum + for (i = 0; i < len; i++) + { + acumulador += (unsigned int)*puntero; + puntero++; + } + // Realizamos dos veces la operacion por el acarreo + acumulador = (acumulador >> 16) + (acumulador & 0x0000ffff); + acumulador = (acumulador >> 16) + (acumulador & 0x0000ffff); + + return (unsigned short)~acumulador; +} +// Función para manejar los errores de ICMP +void errores_ICMP(char type, char code) +{ + switch (type) + { + case 3: // Destination Unreachable + switch (code) + { + case 0: + printf("Destination Unreachable: Net Unreachable\n"); + break; + case 1: + printf("Destination Unreachable: Host Unreachable\n"); + break; + case 2: + printf("Destination Unreachable: Protocol Unreachable\n"); + break; + case 3: + printf("Destination Unreachable: Port Unreachable\n"); + break; + case 4: + printf("Destination Unreachable: Fragmentation Needed\n"); + break; + case 5: + printf("Destination Unreachable: Source Route Failed\n"); + break; + case 6: + printf("Destination Unreachable: Destination Network Unknown\n"); + break; + case 7: + printf("Destination Unreachable: Destination Host Unknown\n"); + break; + case 8: + printf("Destination Unreachable: Source Host Isolated\n"); + break; + case 11: + printf("Destination Unreachable: Destination Network Unreachable for Type of Service\n"); + break; + case 12: + printf("Destination Unreachable: Destination Host Unreachable for Type of Service\n"); + break; + case 13: + printf("Destination Unreachable: Communication Administratively Prohibited\n"); + break; + case 14: + printf("Destination Unreachable: Host Precedence Violation\n"); + break; + case 15: + printf("Destination Unreachable: Precedence Cutoff in Effect\n"); + break; + } + case 5: // Redirect + switch (code) + { + case 1: + printf("Redirect: Redirect for Destination Host\n"); + break; + case 3: + printf("Redirect: Redirect for Destination Host Based on Type-of-Service\n"); + break; + } + case 11: // Time Exceeded + switch (code) + { + case 0: + printf("Time Exceeded: Time-to-Live Exceeded in Transit\n"); + break; + case 1: + printf("Time Exceeded: Fragment Reassembly Time Exceeded\n"); + break; + } + case 12: // Parameter Problem + switch (code) + { + case 0: + printf("Parameter Problem: Pointer indicates the error\n"); + break; + case 1: + printf("Parameter Problem: Missing a Required Option\n"); + break; + case 2: + printf("Parameter Problem: Bad Length\n"); + break; + } + default: + printf("ICMP Error: Type %d, Code %d\n", type, code); + } +} +int main(int argc, char *argv[]) +{ + + struct sockaddr_in direccion; // Estructura para guardar la ip del servidor + int numero_socket; // numero del sockect + int v = 0; // Modo verbose(-v) + socklen_t tam; // Variable para la funcion rcvfrom + struct sockaddr_in myaddr; + + // Comprobamos que el numero de argumentos sea correcto + if (argc < 2 || argc > 3) + { + fprintf(stderr, "Error en el numero de argumentos"); + exit(EXIT_FAILURE); + } + + // Convertimos la dirección IP + if (inet_aton(argv[1], &direccion.sin_addr) == 0) + { + fprintf(stderr, "Error al transformar la direccion IP\n"); + exit(EXIT_FAILURE); + } + + // Creamos el socket UDP + numero_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + if (numero_socket < 0) + { + perror("Error al crear el socket"); + exit(EXIT_FAILURE); + } + // Asignamos la familia a la direccion + direccion.sin_family = AF_INET; + + // Comprobamos si el tercer argumento es modo verbose y inicializamos el flag + if (argc == 3 && strcmp(argv[2], "-v") == 0) + { + v = 1; + } + + printf("-> Enviando Datagrama ICMP a Destino con IP: %s\n", argv[1]); + + // Creamos el mensaje Timestamp + TimeStamp mensaje; + memset(&mensaje, 0, sizeof(mensaje)); + + // Inicializamos la cabecera ICMP + mensaje.icmpHdr.type = 13; + mensaje.icmpHdr.code = 0; + mensaje.pid = getpid(); + mensaje.sequence = 0; + + // Calculamos el tiempo de origen para el mensaje enviado + struct timeval tiempo_ori; + gettimeofday(&tiempo_ori, NULL); + mensaje.originate = tiempo_ori.tv_sec * 1000 + tiempo_ori.tv_usec / 1000; + + // Calculamos checksum y se lo asignamos al mensaje + mensaje.icmpHdr.checksum = 0; + mensaje.icmpHdr.checksum = checksum(&mensaje); + + // Informacion para el modo verbose + if (v) + { + printf("-> Type: %d\n", mensaje.icmpHdr.type); + printf("-> Code: %d\n", mensaje.icmpHdr.code); + printf("-> PID : %d\n", mensaje.pid); + printf("-> Seq Numbr: %d\n", mensaje.sequence); + printf("-> Originate: %u\n", mensaje.originate); + printf("-> Receive: %d\n", mensaje.receive); + printf("-> Transmit: %d\n", mensaje.transmit); + printf("-> Tamanyo del Datagrama: %lu bytes\n", sizeof(mensaje)); + printf("\n"); + } + + // Enviamos el mensaje + int bytes_enviados = sendto(numero_socket, &mensaje, sizeof(mensaje), 0, (struct sockaddr *)&direccion, sizeof(direccion)); + if (bytes_enviados < 0) + { + perror("Error al enviar mensaje"); + exit(EXIT_FAILURE); + } + + printf("-> Timestamp Request enviado correctamente...\n"); + + // Preparar select para tiempo_espera + fd_set sock_lec; + struct timeval tiempo_espera; + + FD_ZERO(&sock_lec); + FD_SET(numero_socket, &sock_lec); + tiempo_espera.tv_sec = tiempo_max; + + // Esperar respuesta con tiempo_espera + int ready = select(numero_socket + 1, &sock_lec, NULL, NULL, &tiempo_espera); + if (ready < 0) + { + perror("Error en select"); + exit(EXIT_FAILURE); + } + + // Recibimos la respuesta + TimeStampReply respuesta; + tam = sizeof(myaddr); + int bytes_recibidos = recvfrom(numero_socket, &respuesta, sizeof(respuesta), 0, (struct sockaddr *)&myaddr, &tam); + if (bytes_recibidos < 0) + { + perror("Error en los bytes recibidos"); + exit(EXIT_FAILURE); + } + + // Calculamos el tiempo de recibir para el mensaje recibido + struct timeval tiempo_rec; + gettimeofday(&tiempo_rec, NULL); + int tiempo_rec_ms = tiempo_rec.tv_sec * 1000 + tiempo_rec.tv_usec / 1000; + + printf("-> Timestamp Reply recibido desde %s\n", inet_ntoa(myaddr.sin_addr)); + // Procesamos la respuesta ICMP + if (respuesta.icmpMsg.icmpHdr.type == 14 && respuesta.icmpMsg.icmpHdr.code == 0) + { + // modo verbose + if (v) + { + printf("-> Originate: %d\n", respuesta.icmpMsg.originate); + printf("-> Receive: %u\n", respuesta.icmpMsg.receive); + printf("-> Transmit: %u\n", respuesta.icmpMsg.transmit); + + // Calcular RTT (RTT = (T2 − T1) + (T4 − T3)) + int rtt = (respuesta.icmpMsg.receive - mensaje.originate) + (tiempo_rec_ms - respuesta.icmpMsg.transmit); + printf("-> RTT: %d miliseconds\n", rtt); + + printf("-> TTL: %d\n", respuesta.ipHdr.TTL); + printf("-> Tamanyo del Datagrama: %lu bytes\n", sizeof(respuesta)); + } + + printf("-> Respuesta Correcta (Type 14, Code 0)\n"); + } + // Si hay errores en la respuesta del mensaje + else if (respuesta.icmpMsg.icmpHdr.type == 3 || respuesta.icmpMsg.icmpHdr.type == 5 || respuesta.icmpMsg.icmpHdr.type == 11 || respuesta.icmpMsg.icmpHdr.type == 12) + + { + errores_ICMP(respuesta.icmpMsg.icmpHdr.type, respuesta.icmpMsg.icmpHdr.code); + } + else + { + printf("-> ICMP Datagram Not Processed...\n"); + } + + return 0; +} \ No newline at end of file -- GitLab