#include #include #include #include #include "dhcp4.h" namespace dhcp4 { int add_parameter_request_list(message * msg, int index) { uint8_t * opt = &msg->options[index]; int length = 3; index += 2 + length; opt[0] = option::parameter_request_list; opt[1] = length; opt[2] = option::subnet_mask; opt[3] = option::router; opt[4] = option::domain_name_server; return index; } int add_uint32(message * msg, int index, uint8_t option, uint32_t value) { uint8_t * opt = &msg->options[index]; int length = 4; index += 2 + length; opt[0] = option; opt[1] = length; memcpy(&opt[2], &value, 4); return index; } int make_message(void * buf, uint32_t bootp_message_type, uint32_t transaction_id, uint8_t const * chaddr, uint32_t dhcp_message_type, message_parameters const * params) { memset(buf, 0, (sizeof (message))); message * msg = reinterpret_cast(buf); msg->op = bootp_message_type; msg->htype = htype::ethernet; msg->hlen = 6; msg->xid = htonl(transaction_id); msg->yiaddr = params->your_ip_address; msg->siaddr = params->next_server_ip_address; memcpy(msg->chaddr, chaddr, 6); int index = 0; uint8_t * cookie = &msg->options[index]; index += 4; cookie[0] = 0x63; cookie[1] = 0x82; cookie[2] = 0x53; cookie[3] = 0x63; uint8_t * message_type = &msg->options[index]; index += 2 + 1; message_type[0] = option::message_type; message_type[1] = 1; // length message_type[2] = dhcp_message_type; if (dhcp_message_type == message_type::dhcpdiscover || dhcp_message_type == message_type::dhcprequest) { index = add_parameter_request_list(msg, index); } if (params->subnet_mask != 0) { index = add_uint32(msg, index, option::subnet_mask, params->subnet_mask); } if (params->server_identifier != 0) { index = add_uint32(msg, index, option::server_identifier, params->server_identifier); index = add_uint32(msg, index, option::ip_address_lease_time, htonl(86400)); } if (params->router != 0) { index = add_uint32(msg, index, option::router, params->router); } if (params->domain_name_server != 0) { index = add_uint32(msg, index, option::domain_name_server, params->domain_name_server); } if (params->requested_ip_address != 0) { index = add_uint32(msg, index, option::requested_ip_address, params->requested_ip_address); } uint8_t * end = &msg->options[index]; index += 1; end[0] = 255; return (sizeof (message)) + index; } char const * message_type_tostr(int message_type) { switch (message_type) { case message_type::dhcpdiscover: return "dhcpdiscover"; case message_type::dhcpoffer: return "dhcpoffer"; case message_type::dhcprequest: return "dhcprequest"; case message_type::dhcpdecline: return "dhcpdecline"; case message_type::dhcpack: return "dhcpack"; case message_type::dhcpnak: return "dhcpnak"; case message_type::dhcprelease: return "dhcprelease"; case message_type::dhcpinform: return "dhcpinform"; default: assert(false); return nullptr; } } void parse_options(message const * m, int options_length, options * o) { uint8_t const * options = m->options; int index = 4; while (index + 2 <= options_length) { int option = options[index + 0]; if (option == option::end) { break; } int option_length = options[index + 1]; switch (option) { case option::message_type: o->message_type = options[index + 2]; break; case option::subnet_mask: o->subnet_mask = *reinterpret_cast(&options[index + 2]); break; case option::router: o->router = *reinterpret_cast(&options[index + 2]); break; case option::domain_name_server: o->domain_name_server = *reinterpret_cast(&options[index + 2]); break; case option::requested_ip_address: o->requested_ip_address = *reinterpret_cast(&options[index + 2]); break; default: break; } index += 2 + option_length; } assert(options[index] == option::end); for (index = index + 1; index < options_length; index++) { assert(options[index] == 0); } } }