#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" int main() { srand(time(NULL)); uint32_t dhcp_transaction_id = rand(); static uint8_t buf[16384]; int sock = sock::create(68); char const * interface_name = "wlp174s0"; 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; ////////////////////////////////////////////////////////////////////// // dhcp send discover ////////////////////////////////////////////////////////////////////// { dhcp4::message_parameters params = { }; int length = packet::make(buf, eth_source_address, eth_destination_address, ip4_source_address, ip4_destination_address, dhcp_transaction_id, dhcp4::message_type::dhcpdiscover, ¶ms); sock::send(sock, ifa_index, buf, length, eth_destination_address); } ////////////////////////////////////////////////////////////////////// // dhcp recv offer ////////////////////////////////////////////////////////////////////// packet::packet p{}; dhcp4::options options{}; uint8_t recvbuf[65536]; { 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); printf("dhcp4 op: %d\n", p.dhcp4->op); printf("dhcp4 yiaddr: %s\n", ip4::tostr(p.dhcp4->yiaddr)); int dhcp4_options_length = rret - (packet::dhcp4_offset + (offsetof (dhcp4::message, options))); dhcp4::parse_options(p.dhcp4, dhcp4_options_length, &options); 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)); 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(buf, eth_source_address, eth_destination_address, ip4_source_address, ip4_destination_address, dhcp_transaction_id, dhcp4::message_type::dhcprequest, ¶ms); sock::send(sock, ifa_index, buf, 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); printf("dhcp4 op: %d\n", p.dhcp4->op); printf("dhcp4 yiaddr: %s\n", ip4::tostr(p.dhcp4->yiaddr)); int dhcp4_options_length = rret - (packet::dhcp4_offset + (offsetof (dhcp4::message, options))); dhcp4::parse_options(p.dhcp4, dhcp4_options_length, &options); 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)); 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); }