Skip to content
Snippets Groups Projects
Commit b2979e1f authored by danredo's avatar danredo
Browse files

Upload New File

parent ccf91b38
No related branches found
No related tags found
No related merge requests found
/**
* Practica Tema 8: ICMP-TIMESTAMP
*
* Apellido, Nombre
* Apellido, Nombre
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <errno.h>
#include "ip-icmp.h" // Usa las estructuras definidas en este archivo
#define ICMP_TIMESTAMP 13
#define ICMP_TIMESTAMP_REPLY 14
#define TIMEOUT 5 // Tiempo de espera en segundos
unsigned short checksum(void *b, int len) {
unsigned short *buf = b;
unsigned int sum = 0;
unsigned short result;
for (sum = 0; len > 1; len -= 2) {
sum += *buf++;
}
if (len == 1) {
sum += *(unsigned char *)buf;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = ~sum;
return result;
}
void print_icmp_error(int type, int code) {
switch (type) {
case 3:
printf("-> Destination Unreachable: ");
switch (code) {
case 0: printf("Net Unreachable\n"); break;
case 1: printf("Host Unreachable\n"); break;
default: printf("Unknown Code\n"); break;
}
break;
default:
printf("-> ICMP Error: Type %d, Code %d\n", type, 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 = 0;
const char *ip = argv[1];
if (argc == 3 && strcmp(argv[2], "-v") == 0) {
verbose = 1;
}
int sockfd;
struct sockaddr_in dest_addr;
struct timeval start_time, end_time;
unsigned char buffer[1024];
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sockfd < 0) {
perror("Error al crear el socket");
return EXIT_FAILURE;
}
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
if (inet_pton(AF_INET, ip, &dest_addr.sin_addr) <= 0) {
perror("Error al convertir la direccion IP");
return EXIT_FAILURE;
}
// Construccion del mensaje ICMP
TimeStamp icmp_msg;
memset(&icmp_msg, 0, sizeof(icmp_msg));
icmp_msg.icmpHdr.type = ICMP_TIMESTAMP;
icmp_msg.icmpHdr.code = 0;
icmp_msg.pid = htons(getpid());
icmp_msg.sequence = htons(0);
gettimeofday(&start_time, NULL);
icmp_msg.originate = htonl((start_time.tv_sec * 1000) + (start_time.tv_usec / 1000));
icmp_msg.receive = 0; // Inicializar campo Receive a 0
icmp_msg.transmit = 0; // Inicializar campo Transmit a 0
int icmp_length = sizeof(icmp_msg); // Tamaño dinámico en caso de relleno
icmp_msg.icmpHdr.checksum = checksum(&icmp_msg, icmp_length); // Calculo y asignacion del checksum
// Enviar el mensaje
if (sendto(sockfd, &icmp_msg, sizeof(icmp_msg), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) < 0) {
perror("Error al enviar el datagrama");
return EXIT_FAILURE;
}
if (verbose) {
printf("-> Enviando Datagrama ICMP a Destino con IP: %s\n", ip);
}
// Configuracion del tiempo de espera
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sockfd, &readfds);
struct timeval timeout;
timeout.tv_sec = TIMEOUT;
timeout.tv_usec = 0;
int sel = select(sockfd + 1, &readfds, NULL, NULL, &timeout);
if (sel == -1) {
perror("Error en select");
return EXIT_FAILURE;
} else if (sel == 0) {
printf("-> Tiempo de espera agotado para el destino %s.\n", ip);
return EXIT_FAILURE;
}
// Recibir la respuesta
socklen_t addr_len = sizeof(dest_addr);
if (recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&dest_addr, &addr_len) < 0) {
perror("Error al recibir el datagrama");
return EXIT_FAILURE;
}
gettimeofday(&end_time, NULL);
// Excluir cabecera IP
struct iphdr *ip_hdr = (struct iphdr *)buffer;
int ip_header_length = ip_hdr->ihl * 4;
TimeStamp *recv_reply = (TimeStamp *)(buffer + ip_header_length);
// Verificar el checksum del datagrama recibido
unsigned short recv_checksum = recv_reply->icmpHdr.checksum;
recv_reply->icmpHdr.checksum = 0; // Temporalmente establece a 0 para recalcular
int recv_len = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&dest_addr, &addr_len);
if (recv_len < 0) {
perror("Error al recibir el datagrama");
return EXIT_FAILURE;
}
icmp_length = recv_len - ip_header_length;
if (checksum(recv_reply, icmp_length) != 0) {
fprintf(stderr, "Error: Checksum invalido en el datagrama recibido.\n");
return EXIT_FAILURE;
}
recv_reply->icmpHdr.checksum = recv_checksum; // Restaurar el valor original
if (recv_reply->icmpHdr.type == ICMP_TIMESTAMP_REPLY) {
unsigned long originate = ntohl(recv_reply->originate);
unsigned long receive = ntohl(recv_reply->receive);
unsigned long transmit = ntohl(recv_reply->transmit);
unsigned long t4 = (end_time.tv_sec * 1000) + (end_time.tv_usec / 1000);
unsigned long rtt = (receive - originate) + (t4 - transmit);
// Mensajes que se imprimen siempre
printf("-> Timestamp Reply recibido desde %s\n", ip);
printf("-> Respuesta Correcta (Type %d, Code %d)\n", recv_reply->icmpHdr.type, recv_reply->icmpHdr.code);
// Mensajes que solo se imprimen con -v
if (verbose) {
printf("-> Originate (recibido): %lu\n", originate);
printf("-> Receive (recibido): %lu\n", receive);
printf("-> Transmit (recibido): %lu\n", transmit);
printf("-> T4 (local): %lu\n", t4);
printf("-> RTT: %lu ms\n", rtt);
printf("-> TTL: %d\n", ip_hdr->ttl);
printf("-> Tamanyo del Datagrama: %zu bytes\n", sizeof(buffer));
}
// Si algun tiempo es 0, el destino no ha procesado los campos
if (receive == 0 || transmit == 0) {
fprintf(stderr, "Error: El destino no procesa correctamente los campos Receive (%lu) o Transmit (%lu).\n", receive, transmit);
return EXIT_FAILURE;
}
// Error si: el tiempo en que se recibio el mensaje es menor al tiempo en que se envio,
// el tiempo en que se transmitio la respuesta es menor que el tiempo en que se recibio,
// o el tiempo en que se recibio la respuesta del origen (t4) es menor al tiempo de transmision de la respuesta
if (receive < originate || transmit < receive || t4 < transmit) {
fprintf(stderr, "Error: Valores de marcas de tiempo inconsistentes.\n");
return EXIT_FAILURE;
}
} else {
print_icmp_error(recv_reply->icmpHdr.type, recv_reply->icmpHdr.code);
}
close(sockfd);
return EXIT_SUCCESS;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment