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;
+}