#include #include #include #include #include #include #include #include #include #include "ip4.h" #include "udp4.h" #include "dhcp4.h" #include "eth.h" #include "packet.h" #include "interface.h" #include "sock.h" void print_message(packet::packet const& p, dhcp4::options const& options) { printf("dhcp4 op: %d\n", p.dhcp4->op); printf("dhcp4 yiaddr: %s\n", ip4::tostr(p.dhcp4->yiaddr)); printf("message type: %s\n", dhcp4::message_type_tostr(options.message_type)); printf("subnet mask: %s\n", ip4::tostr(options.subnet_mask)); printf("router: %s\n", ip4::tostr(options.router)); printf("domain name server: %s\n", ip4::tostr(options.domain_name_server)); } int main(int argc, char * argv[]) { if (argc != 2) { fprintf(stderr, "usage: %s [interface-name]\n", argv[0]); exit(EXIT_FAILURE); } char const * interface_name = argv[1]; printf("interface name: %s\n", interface_name); srand(time(NULL)); uint32_t dhcp_transaction_id = rand(); int sock = sock::create(68); 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); uint8_t eth_destination_address[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; uint32_t ip4_source_address = 0x00000000; uint32_t ip4_destination_address = 0xffffffff; packet::packet p{}; dhcp4::options options{}; static uint8_t recvbuf[65536]; static uint8_t sendbuf[16384]; ////////////////////////////////////////////////////////////////////// // dhcp send discover ////////////////////////////////////////////////////////////////////// { dhcp4::message_parameters params = { }; int length = packet::make(sendbuf, dhcp4::op::bootrequest, eth_source_address, eth_destination_address, eth_source_address, // eth_client_address ip4_source_address, ip4_destination_address, 68, // udp4_source_port 67, // udp4_destination_port dhcp_transaction_id, dhcp4::message_type::dhcpdiscover, ¶ms); sock::send(sock, ifa_index, sendbuf, length, eth_destination_address); } ////////////////////////////////////////////////////////////////////// // dhcp recv offer ////////////////////////////////////////////////////////////////////// { 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); print_message(p, options); assert(p.dhcp4->op == dhcp4::op::bootreply); assert(options.message_type == dhcp4::message_type::dhcpoffer); } ////////////////////////////////////////////////////////////////////// // dhcp send request ////////////////////////////////////////////////////////////////////// { dhcp4::message_parameters params = { .requested_ip_address = p.dhcp4->yiaddr, }; int length = packet::make(sendbuf, dhcp4::op::bootrequest, eth_source_address, eth_destination_address, eth_source_address, // eth_client_address ip4_source_address, ip4_destination_address, 68, // udp4_source_port 67, // udp4_destination_port dhcp_transaction_id, dhcp4::message_type::dhcprequest, ¶ms); sock::send(sock, ifa_index, sendbuf, length, eth_destination_address); } ////////////////////////////////////////////////////////////////////// // dhcp recv ack ////////////////////////////////////////////////////////////////////// { 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); print_message(p, options); assert(p.dhcp4->op == dhcp4::op::bootreply); assert(options.message_type == dhcp4::message_type::dhcpack); } ////////////////////////////////////////////////////////////////////// // interface configure ////////////////////////////////////////////////////////////////////// uint32_t mask = ntohl(options.subnet_mask); uint8_t prefix_length = 32 - __builtin_ctz(mask); printf("prefix_length %d\n", prefix_length); interface::configure(ifa_index, prefix_length, p.dhcp4->yiaddr, options.router); ////////////////////////////////////////////////////////////////////// // dns configure ////////////////////////////////////////////////////////////////////// int dfd = open("/etc/resolv.conf", O_CREAT | O_WRONLY | O_TRUNC); if (dfd < 0) { perror("open"); exit(EXIT_FAILURE); } char dbuf[1024]; int dbuflen = snprintf(dbuf, (sizeof (dbuf)), "nameserver %s\n", ip4::tostr(options.domain_name_server)); if (dbuflen < 0) { perror("snprintf"); exit(EXIT_FAILURE); } ssize_t dret = write(dfd, dbuf, dbuflen); if (dret < 0) { perror("write"); exit(EXIT_FAILURE); } ////////////////////////////////////////////////////////////////////// // exit ////////////////////////////////////////////////////////////////////// close(dfd); close(sock); exit(EXIT_SUCCESS); }