dhcp/server.cpp

132 lines
4.8 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stddef.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include "ip4.h"
#include "udp4.h"
#include "dhcp4.h"
#include "eth.h"
#include "packet.h"
#include "interface.h"
#include "sock.h"
int main()
{
int sock = sock::create(67);
char const * interface_name = "enp175s0";
int ifa_index = sock::interface_index(sock, interface_name);
sock::bind_interface(sock, ifa_index);
uint8_t eth_source_address[6];
sock::interface_address(sock, interface_name, eth_source_address);
packet::packet p{};
dhcp4::options options{};
static uint8_t recvbuf[65536];
static uint8_t sendbuf[16384];
uint32_t ip4_client_address = ip4::fromstr("10.0.0.50");
uint32_t ip4_server_address = ip4::fromstr("10.0.0.5");
uint32_t ip4_subnet_mask = ip4::fromstr("255.255.255.0");
uint32_t ip4_router = ip4::fromstr("10.0.0.5");
uint32_t ip4_domain_name_server = ip4::fromstr("8.8.8.8");
while (true) {
//////////////////////////////////////////////////////////////////////
// dhcp recv
//////////////////////////////////////////////////////////////////////
{
struct sockaddr_ll recv_address;
int flags = 0;
socklen_t socklen = (sizeof (struct sockaddr_ll));
ssize_t rret = recvfrom(sock, recvbuf, (sizeof (recvbuf)), flags,
(struct sockaddr *)&recv_address, &socklen);
if (rret < 0) {
perror("recvfrom");
exit(EXIT_FAILURE);
}
packet::parse(recvbuf, rret, &p);
int dhcp4_options_length = rret - (packet::dhcp4_offset + (offsetof (dhcp4::message, options)));
dhcp4::parse_options(p.dhcp4, dhcp4_options_length, &options);
printf("dhcp4 op: %d\n", p.dhcp4->op);
printf("message type: %s\n", dhcp4::message_type_tostr(options.message_type));
printf("transaction id: %08x\n", ntohl(p.dhcp4->xid));
}
if (options.message_type == dhcp4::message_type::dhcpdiscover) {
dhcp4::message_parameters params = {
.your_ip_address = ip4_client_address,
.next_server_ip_address = ip4_server_address,
.server_identifier = ip4_server_address,
.subnet_mask = ip4_subnet_mask,
.router = ip4_router,
.domain_name_server = ip4_domain_name_server,
};
uint8_t const * eth_destination_address = p.eth->source_address;
uint32_t ip4_source_address = ip4_server_address;
uint32_t ip4_destination_address = ip4_client_address;
uint32_t dhcp_transaction_id = ntohl(p.dhcp4->xid);
int length = packet::make(sendbuf,
dhcp4::op::bootreply,
eth_source_address,
eth_destination_address,
eth_destination_address, // eth_client_address
ip4_source_address,
ip4_destination_address,
67,
68,
dhcp_transaction_id,
dhcp4::message_type::dhcpoffer,
&params);
sock::send(sock, ifa_index, sendbuf, length, eth_destination_address);
}
if (options.message_type == dhcp4::message_type::dhcprequest) {
printf("requested ip address: %s\n", ip4::tostr(options.requested_ip_address));
if (options.requested_ip_address != ip4_client_address) {
printf("should NAK\n");
continue;
}
dhcp4::message_parameters params = {
.your_ip_address = ip4_client_address,
.next_server_ip_address = ip4_server_address,
.server_identifier = ip4_server_address,
.subnet_mask = ip4_subnet_mask,
.router = ip4_router,
.domain_name_server = ip4_domain_name_server,
};
uint8_t const * eth_destination_address = p.eth->source_address;
uint32_t ip4_source_address = ip4_server_address;
uint32_t ip4_destination_address = ip4_client_address;
uint32_t dhcp_transaction_id = ntohl(p.dhcp4->xid);
int length = packet::make(sendbuf,
dhcp4::op::bootreply,
eth_source_address,
eth_destination_address,
eth_destination_address, // eth_client_address
ip4_source_address,
ip4_destination_address,
67,
68,
dhcp_transaction_id,
dhcp4::message_type::dhcpack,
&params);
sock::send(sock, ifa_index, sendbuf, length, eth_destination_address);
}
}
}