diff --git a/.idea/DHCP-implementation.iml b/.idea/DHCP-implementation.iml deleted file mode 100644 index bc2cd87..0000000 --- a/.idea/DHCP-implementation.iml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..53624c9 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 70baabb..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/bin/client b/bin/client index 23e4a34..2ccdb50 100755 Binary files a/bin/client and b/bin/client differ diff --git a/bin/server b/bin/server new file mode 100755 index 0000000..a7f659b Binary files /dev/null and b/bin/server differ diff --git a/include/dhcp_server.h b/include/dhcp_server.h new file mode 100644 index 0000000..8f01fa7 --- /dev/null +++ b/include/dhcp_server.h @@ -0,0 +1,9 @@ +#ifndef DHCP_SERVER_H +#define DHCP_SERVER_H + +#include +#include + +int run_server(void); + +#endif diff --git a/include/net_utils.h b/include/net_utils.h index 5b7f13b..dced45d 100644 --- a/include/net_utils.h +++ b/include/net_utils.h @@ -1,11 +1,11 @@ #ifndef NET_UTILS_H #define NET_UTILS_H -#include #include +#include +#include #include #include -#include #define DHCP_SNAME_SIZE 64 #define DHCP_FILE_SIZE 128 @@ -51,10 +51,12 @@ enum DHCP_MESSAGE { DHCP_INFORM = 8, }; +int get_dhcp_type(DHCPPacket *packet); + // --- DECLARACIONES CORRECTAS Y FINALES --- // Corregido el nombre a "get_mac_address" y la firma int get_mac_address(const char *if_name, uint8_t *mac_buffer); // Corregida la firma para aceptar un puntero a la MAC -DHCPPacket create_dhcp_packet(uint8_t *mac_addr, enum DHCP_OP op, enum DHCP_MESSAGE tipo_msg, size_t *packet_size); +DHCPPacket create_dhcp_packet(uint32_t xid, uint8_t *mac_addr, enum DHCP_MESSAGE tipo_msg, uint32_t *requested_ip, uint32_t *server_id, size_t *packet_size); -#endif \ No newline at end of file +#endif diff --git a/makefile b/makefile index b1a8a78..8a5a9ca 100644 --- a/makefile +++ b/makefile @@ -2,18 +2,22 @@ CC = gcc CFLAGS = -Wall -Wextra -Iinclude SRC_DIR = src BIN_DIR = bin -SRC = $(wildcard $(SRC_DIR)/*.c) -OBJ = $(SRC:.c=.o) -BIN = $(BIN_DIR)/client +CLIENT_SRC = $(SRC_DIR)/main.c $(SRC_DIR)/dhcp_client.c $(SRC_DIR)/net_utils.c +SERVER_SRC = $(SRC_DIR)/main.c $(SRC_DIR)/dhcp_server.c $(SRC_DIR)/net_utils.c +CLIENT_BIN = $(BIN_DIR)/client +SERVER_BIN = $(BIN_DIR)/server -.PHONY: all clean +.PHONY: all clean client server -$(BIN): $(OBJ) +all: client server + +client: $(CLIENT_SRC) @mkdir -p $(BIN_DIR) - $(CC) $(CFLAGS) $^ -o $@ + $(CC) $(CFLAGS) -DCLIENT_MAIN $(CLIENT_SRC) -o $(CLIENT_BIN) -%.o: %.c - $(CC) $(CFLAGS) -c $< -o $@ +server: $(SERVER_SRC) + @mkdir -p $(BIN_DIR) + $(CC) $(CFLAGS) -DSERVER_MAIN $(SERVER_SRC) -o $(SERVER_BIN) clean: - rm -f $(OBJ) $(BIN) \ No newline at end of file + rm -f $(BIN_DIR)/client $(BIN_DIR)/server \ No newline at end of file diff --git a/src/dhcp_client.c b/src/dhcp_client.c index 80b1f0b..4d83290 100644 --- a/src/dhcp_client.c +++ b/src/dhcp_client.c @@ -20,7 +20,7 @@ int start_client(const char *if_name) { srand(time(0)); uint8_t mac_addr[6]; - const char *interface_name = "enp7s0"; + const char *interface_name = "wlo1"; if (get_mac_address(interface_name, mac_addr) != 0) { fprintf(stderr, "No se pudo obtener la dirección MAC de la interfaz %s\n", interface_name); @@ -31,8 +31,13 @@ int start_client(const char *if_name) { mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + //Generar el xid una SOLA VEZ + uint32_t xid = htonl((uint32_t)rand()); //Rand genera el numero y htonl lo convierte a big-endian + size_t packet_size; - DHCPPacket dhcp_packet = create_dhcp_packet(mac_addr, BOOTREQUEST, DHCP_DISCOVER, &packet_size); + + //NULL La ip solicitada y el server_id, porque no los tenemos xd + DHCPPacket dhcp_packet = create_dhcp_packet(xid, mac_addr, DHCP_DISCOVER, NULL,NULL, &packet_size); int socket_fd; struct sockaddr_in server_addr; @@ -105,20 +110,115 @@ int start_client(const char *if_name) { printf("Paquete recibido (%ld bytes)\n", recibido); DHCPPacket *respuesta = (DHCPPacket *)buffer; - if (respuesta->op != BOOTREPLY) { - printf("Respuesta no válida: op = %d\n", respuesta->op); + if(respuesta->op != BOOTREPLY || respuesta->xid != xid) { + printf("Respuesta no válida o xid no coincide\n"); close(socket_fd); return EXIT_FAILURE; } printf("IP ofrecida: %s\n", inet_ntoa(*(struct in_addr *)&respuesta->yiaddr)); + // PARTE DEL REQUEST DEL CLIENTE AL SERVIDOR + + //1. Definir una funcion get server id que reciba la respuesta del servidor y extraiga el server_id + + uint32_t get_server_id(DHCPPacket *pkt) { + uint8_t *options = pkt->options; + uint8_t *ptr = options + 4; // Saltar el magic cookie + uint8_t *end = options + DHCP_OPTIONS_SIZE; + while (ptr < end && *ptr != 255) { + uint8_t opt_code = *ptr++; + if (opt_code == 0) { + continue; + } + uint8_t opt_len = *ptr++; + if (opt_code == 54) { + uint32_t server_id; + memcpy(&server_id, ptr, sizeof(server_id)); + return server_id; + } + ptr += opt_len; + } + return 0; + } + + enum DHCP_MESSAGE get_dhcp_message_type(DHCPPacket *pkt) { + uint8_t *options = pkt->options; + uint8_t *ptr = options + 4; // Saltar el magic cookie + uint8_t *end = options + DHCP_OPTIONS_SIZE; + while (ptr < end && *ptr != 255) { + uint8_t opt_code = *ptr++; + if (opt_code == 0) { + continue; + } + uint8_t opt_len = *ptr++; + if (opt_code == 53) { + return (enum DHCP_MESSAGE)*ptr; + } + ptr += opt_len; + } + return 0; + } + + uint32_t server_id = get_server_id(respuesta); + + if (server_id == 0) { + printf("No se encontró el Server Identifier en la respuesta\n"); + close(socket_fd); + return EXIT_FAILURE; + } + + size_t request_packet_size; + DHCPPacket dhcp_request = create_dhcp_packet(xid, mac_addr, DHCP_REQUEST, &respuesta->yiaddr, &server_id, &request_packet_size); + + if (sendto(socket_fd, &dhcp_request, request_packet_size, 0, + (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + perror("Error al enviar el paquete DHCP REQUEST"); + close(socket_fd); + return EXIT_FAILURE; + } + + printf("Paquete dhcp REQUEST enviado (%ld bytes)\n", request_packet_size); + + printf("Pedimos la IP %s al servidor con ID %s\n", + inet_ntoa(*(struct in_addr *)&respuesta->yiaddr), + inet_ntoa(*(struct in_addr *)&server_id)); - // PARTE DEL REQUEST DEL CLIENTE AL SERVIDOR + printf("Esperando respuesta DHCP ACK o NAK...\n"); + + memset(buffer, 0, sizeof(buffer)); - // Supongo que primero hay que crear el fuquin paquete: + recibido = recvfrom(socket_fd, buffer, sizeof(buffer), 0, NULL, NULL); + + if (recibido < 0) { + perror("Error al recibir paquete DHCP ACK o NAK"); + close(socket_fd); + return EXIT_FAILURE; + } - // DHCPPacket dhcp_request = create_dhcp_packet(); + printf("Paquete recibido (%ld bytes)\n", recibido); + + DHCPPacket *respuesta_final = (DHCPPacket *)buffer; + + if(respuesta_final->xid != xid) { + printf("Respuesta no válida o xid no coincide\n"); + close(socket_fd); + return EXIT_FAILURE; + } + + enum DHCP_MESSAGE msg_type = get_dhcp_message_type(respuesta_final); + + switch (msg_type) { + case DHCP_ACK: + printf("Mensaje tipo DHCP_ACK recibido\n"); + break; + case DHCP_NAK: + printf("Mensaje tipo DHCP_NAK recibido\n"); + break; + default: + printf("Mensaje tipo desconocido recibido: %d\n", msg_type); + break; + } close(socket_fd); return 0; diff --git a/src/dhcp_server.c b/src/dhcp_server.c index 96367c4..33718a7 100644 --- a/src/dhcp_server.c +++ b/src/dhcp_server.c @@ -1,2 +1,146 @@ -//DHCP server w/ include dchp_packet.h and net_utils.h -#include "net_utils.h" \ No newline at end of file +// DHCP server w/ include dchp_packet.h and net_utils.h +#include "net_utils.h" +#include +#include +#include +#include +#include +#include +#include +#include + +uint8_t buffer[1024]; + +struct sockaddr_in client_addr; +struct sockaddr_in server_addr; + +socklen_t client_addr_len = sizeof(client_addr); + +DHCPPacket build_packet_for_offer(DHCPPacket *packet); + +int init_server() { + int socket_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (socket_fd < 0) { + perror("DHCP server socket failed"); + return -1; + } + printf("DHCP server socket created successfully (fd: %d)\n", socket_fd); + + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(67); + server_addr.sin_addr.s_addr = INADDR_ANY; + + int broadcast = 1; + + setsockopt(socket_fd, SOL_SOCKET, SO_BROADCAST, &broadcast, + sizeof(broadcast)); + + int result = + bind(socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)); + + if (result < 0) { + perror("bind failed"); + return -1; + } + + printf("DHCP server bound to port 67 successfully\n"); + return socket_fd; +} + +int receive_packet(int socket_fd) { + ssize_t len = recvfrom(socket_fd, buffer, sizeof(buffer), 0, + (struct sockaddr *)&client_addr, &client_addr_len); + if (len < 0) { + perror("elpepe receive error message"); + return -1; + } + return len; +} + +int run_server() { + + printf("Initializing DHCP server...\n"); + int fd = init_server(); + if (fd < 0) { + fprintf(stderr, "[FATAL] No se pudo inicializar el socket del servidor DHCP. Terminando.\n"); + return EXIT_FAILURE; + } + while (1) { + int len = receive_packet(fd); + if (len == -1) { + continue; + } + + DHCPPacket *packet = (DHCPPacket *)buffer; + + if (packet->op != 1) { + continue; + } + + int packet_type = get_dhcp_type(packet); + printf("Received Packet\n"); + + if(packet_type == DHCP_DISCOVER){ + printf("Received DHCP_DISCOVER message\n"); + + + DHCPPacket packet_to_send = build_packet_for_offer(packet); + + size_t packet_size = sizeof(DHCPPacket); + + struct sockaddr_in reply_addr; + memset(&reply_addr, 0, sizeof(reply_addr)); + + reply_addr.sin_family = AF_INET; + reply_addr.sin_port = htons(68); + + if(packet->ciaddr != 0){ + reply_addr.sin_addr.s_addr = packet->ciaddr; + } else { + reply_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); + } + + size_t sent_bytes = sendto(fd, &packet_to_send, packet_size,0, (struct sockaddr*)&reply_addr, sizeof(reply_addr)); + + if(sent_bytes < 0){ + perror("Can not reply the DHCP Packet"); + return EXIT_FAILURE; + } else { + printf("DHCP OFFER sent successfully (%zd bytes) \n", sent_bytes); + } + } + /* printf("Packet type: %d\n", packet_type); */ + } + + close(fd); + return 0; +} + +DHCPPacket build_packet_for_offer(DHCPPacket *req_packet) { + DHCPPacket packet; + + memset(&packet, 0, sizeof(DHCPPacket)); + + packet.op = BOOTREPLY; + packet.htype = Ethernet; + packet.hlen = 6; + packet.xid = req_packet->xid; + packet.flags = req_packet->flags; + + memcpy(packet.chaddr, req_packet->chaddr, 6); + + + + uint8_t *opt_ptr = packet.options; + + memcpy(opt_ptr, MAGIC_COOKIE, 4); + + opt_ptr += 4; + *opt_ptr++ = 53; + *opt_ptr++ = 1; + *opt_ptr++ = DHCP_OFFER; + *opt_ptr++ = 255; + + return packet; +} diff --git a/src/main.c b/src/main.c index 9be49ff..91a32c2 100644 --- a/src/main.c +++ b/src/main.c @@ -1,17 +1,43 @@ #include "dhcp_client.h" +#include "dhcp_server.h" #include #include +#include int main(int argc, char *argv[]) { - if(argc < 2) { - fprintf(stderr, "Uso: %s \n", argv[0]); - return 1; - } - - if (start_client(argv[1]) != 0) { - fprintf(stderr, "Error al iniciar el cliente DHCP.\n"); - return 1; - } - - return EXIT_SUCCESS; +#ifdef CLIENT_MAIN + if (argc < 2) { + fprintf(stderr, "Uso: %s \n", argv[0]); + return 1; + } + if (start_client(argv[1]) != 0) { + fprintf(stderr, "Error al iniciar el cliente DHCP.\n"); + return 1; + } + return EXIT_SUCCESS; +#elif defined(SERVER_MAIN) + return run_server(); +#else + if (argc < 2) { + fprintf(stderr, "Uso: %s [nombre_de_interfaz]\n", argv[0]); + return 1; + } + if (strcmp(argv[1], "server") == 0) { + return run_server(); + } else if (strcmp(argv[1], "client") == 0) { + if (argc < 3) { + fprintf(stderr, "Uso: %s client \n", argv[0]); + return 1; + } + if (start_client(argv[2]) != 0) { + fprintf(stderr, "Error al iniciar el cliente DHCP.\n"); + return 1; + } + return EXIT_SUCCESS; + } else { + fprintf(stderr, "Opción desconocida: %s\n", argv[1]); + fprintf(stderr, "Uso: %s [nombre_de_interfaz]\n", argv[0]); + return 1; + } +#endif } diff --git a/src/net_utils.c b/src/net_utils.c index 69850b0..4adce7e 100644 --- a/src/net_utils.c +++ b/src/net_utils.c @@ -1,71 +1,96 @@ #include "net_utils.h" -#include -#include #include +#include #include -#include -#include +#include +#include +#include #include +#include #include -#include +#include +#include const uint8_t MAGIC_COOKIE[4] = {99, 130, 83, 99}; -int get_mac_address(const char *if_name, uint8_t *mac_buffer) { - struct ifreq ifr; - int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); - if (sock < 0) { - perror("socket"); - return -1; - } - - strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1); - ifr.ifr_name[IFNAMSIZ - 1] = '\0'; - - if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) { - perror("ioctl"); - close(sock); - return -1; +int get_dhcp_type(DHCPPacket *packet) { + for (size_t i = 0; i < sizeof(packet->options); i++) { + if (packet->options[i] == 53) { + return packet->options[i + 2]; // Value is two bytes to the right. } + } + return -1; +} +int get_mac_address(const char *if_name, uint8_t *mac_buffer) { + struct ifreq ifr; + int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (sock < 0) { + perror("socket"); + return -1; + } + + strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1); + ifr.ifr_name[IFNAMSIZ - 1] = '\0'; + + if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) { + perror("ioctl"); close(sock); + return -1; + } + + close(sock); - // Copia los 6 bytes de la MAC directamente al buffer - memcpy(mac_buffer, ifr.ifr_hwaddr.sa_data, 6); + // Copia los 6 bytes de la MAC directamente al buffer + memcpy(mac_buffer, ifr.ifr_hwaddr.sa_data, 6); - return 0; // Éxito + return 0; // Éxito } +DHCPPacket create_dhcp_packet(uint32_t xid, uint8_t *mac_addr, enum DHCP_MESSAGE tipo_msg, uint32_t *requested_ip, uint32_t *server_id, size_t *packet_size) { + DHCPPacket pkt; + memset(&pkt, 0, sizeof(DHCPPacket)); + pkt.op = (tipo_msg == DHCP_DISCOVER) ? BOOTREQUEST : BOOTREQUEST; + pkt.htype = Ethernet; + pkt.hlen = 6; + pkt.xid = xid; + pkt.flags = htons(0x8000); -DHCPPacket create_dhcp_packet(uint8_t *mac_addr, enum DHCP_OP op, enum DHCP_MESSAGE tipo_msg, size_t *packet_size) { - DHCPPacket pkt; - memset(&pkt, 0, sizeof(DHCPPacket)); + // Copia la MAC (array de bytes) al campo chaddr del paquete + memcpy(pkt.chaddr, mac_addr, 6); - pkt.op = op; - pkt.htype = Ethernet; - pkt.hlen = 6; - pkt.xid = htonl((uint32_t)rand()); - pkt.flags = htons(0x8000); + uint8_t *opt_ptr = pkt.options; - // Copia la MAC (array de bytes) al campo chaddr del paquete - memcpy(pkt.chaddr, mac_addr, 6); + // Magic Cookie + memcpy(opt_ptr, MAGIC_COOKIE, 4); + opt_ptr += 4; - uint8_t *opt_ptr = pkt.options; + // Opción 53: DHCP Message Type + *opt_ptr++ = 53; + *opt_ptr++ = 1; + *opt_ptr++ = tipo_msg; - // Magic Cookie - memcpy(opt_ptr, MAGIC_COOKIE, 4); + // Si es REQUEST y hay IP solicitada, agregar opción 50 + if (tipo_msg == DHCP_REQUEST && requested_ip != NULL) { + *opt_ptr++ = 50; // Option 50: Requested IP Address + *opt_ptr++ = 4; + memcpy(opt_ptr, requested_ip, 4); opt_ptr += 4; + } - // Opción 53: DHCP Message Type - *opt_ptr++ = 53; - *opt_ptr++ = 1; - *opt_ptr++ = tipo_msg; + // Si es REQUEST y hay server_id, agregar opción 54 + if (tipo_msg == DHCP_REQUEST && server_id != NULL) { + *opt_ptr++ = 54; // Option 54: Server Identifier + *opt_ptr++ = 4; + memcpy(opt_ptr, server_id, 4); + opt_ptr += 4; + } - // Opción 255: End - *opt_ptr++ = 255; + // Opción 255: End + *opt_ptr++ = 255; - *packet_size = (size_t)(opt_ptr - (uint8_t *)&pkt); + *packet_size = sizeof(DHCPPacket); // Se envía el struct completo - return pkt; -} \ No newline at end of file + return pkt; +}