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

Upload New File

parent febad159
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 <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;
unsigned char buffer[1024];
// 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;
if (inet_pton(AF_INET, ip, &dest_addr.sin_addr) <= 0) {
perror("Error al convertir la dirección IP");
exit(EXIT_FAILURE);
}
// Construir el mensaje ICMP
TimeStamp icmp_msg;
crearICMPRequest(&icmp_msg);
// En modo verbose, imprime siempre 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", ntohs(icmp_msg.pid));
printf("-> Seq Numbr: %d\n", ntohs(icmp_msg.sequence));
printf("-> Originate: %u ms\n", ntohl(icmp_msg.originate));
printf("-> Receive: 0 ms\n"); // Los campos Receive y Transmit no están en icmp_msg
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");
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) {
printf("-> Tiempo de espera agotado para %s\n", ip);
exit(EXIT_FAILURE);
}
// Recibir respuesta
TimeStampReply *recv_reply;
memset(icmp_msg, 0, sizeof(TimeStamp));
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");
exit(EXIT_FAILURE);
}
// Verificar tipo de respuesta
if (recv_reply->icmpMsg.icmpHdr.type == ICMP_TIMESTAMP_REPLY && recv_reply->icmpMsg.icmpHdr.code == 0) {
printf("\n-> Timestamp Reply recibido desde %s\n", ip);
if (strcmp(ip, "127.0.0.1") == 0) { // Caso especial: Loopback
printf("-> ICMP Datagram Not Processed...\n");
} else {
unsigned long originate = ntohl(recv_reply->icmpMsg.originate);
unsigned long receive = recv_reply->icmpMsg.receive;
unsigned long transmit = recv_reply->icmpMsg.transmit;
struct timeval end_time;
gettimeofday(&end_time, NULL);
unsigned long t4 = ((unsigned long)end_time.tv_sec * 1000) + ((unsigned long)end_time.tv_usec / 1000);
printf("\n%lu\n", t4);
unsigned long rtt = (receive - originate) + (t4 - transmit);
if (verbose) {
printf("-> Originate: %lu ms\n", originate);
printf("-> Receive: %lu ms\n", receive);
printf("-> Transmit: %lu ms\n", transmit);
printf("-> RTT: %lu 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 {
// Caso de error genérico o inesperado
imprimeError(recv_reply->icmpMsg.icmpHdr.type, recv_reply->icmpMsg.icmpHdr.code);
}
close(sockfd);
return EXIT_SUCCESS;
}
// Función para inicializar el mensaje ICMP
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 = htons(getpid());
icmp_msg->sequence = htons(0);
struct timeval start_time;
gettimeofday(&start_time, NULL);
icmp_msg->originate = htonl((start_time.tv_sec * 1000) + (start_time.tv_usec / 1000));
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;
for (; len > 1; len -= 2) sum += *buf++;
if (len == 1) sum += *(unsigned char *)buf;
sum = (sum >> 16) + (sum & 0xFFFF);
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
mensaje = "-> 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 mensaje = "-> Destination Unreachable: Unknown Code";
} else if (type == 11) { // Time Exceeded
mensaje = "-> Time Exceeded";
} else { // Otros tipos de error ICMP
mensaje = "-> ICMP Error: ";
}
// Imprimir el mensaje final
printf("%s (Type %d, Code %d)\n", mensaje, type, code);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment