#include #include #include #include #include #include #include #include #include #include #include #include #include #include "ipv4.h" #include "udp4.h" #include "dhcp4.h" #include "eth.h" int make_packet(uint8_t * buf, uint8_t const * eth_source_address, uint8_t const * eth_destination_address, uint32_t const ipv4_source_address, uint32_t const ipv4_destination_address, uint32_t const dhcp_transaction_id, uint32_t const dhcp_message_type) { ////////////////////////////////////////////////////////////////////// // dhcp4 ////////////////////////////////////////////////////////////////////// int dhcp4_offset = (sizeof (eth::header)) + (sizeof (ipv4::header)) + (sizeof (udp4::header)); int dhcp4_length = dhcp4::make_message(reinterpret_cast(&buf[dhcp4_offset]), dhcp4::op::bootrequest, dhcp_transaction_id, eth_source_address, dhcp_message_type); ////////////////////////////////////////////////////////////////////// // eth ////////////////////////////////////////////////////////////////////// int eth_offset = 0; eth::header * eth_header = reinterpret_cast(&buf[eth_offset]); memcpy(eth_header->destination_address, eth_destination_address, 6); memcpy(eth_header->source_address, eth_source_address, 6); eth_header->ether_type = htons(0x0800); ////////////////////////////////////////////////////////////////////// // ipv4 ////////////////////////////////////////////////////////////////////// int ipv4_offset = (sizeof (eth::header)); int ipv4_payload_length = dhcp4_length + (sizeof (udp4::header)); int ipv4_identification = 55179; ipv4::make_header(reinterpret_cast(&buf[ipv4_offset]), ipv4_payload_length, ipv4_identification, ipv4_source_address, ipv4_destination_address); ////////////////////////////////////////////////////////////////////// // udp4 ////////////////////////////////////////////////////////////////////// int udp4_offset = (sizeof (eth::header)) + (sizeof (ipv4::header)); udp4::make_header(reinterpret_cast(&buf[udp4_offset]), htons(68), htons(67), ipv4_source_address, ipv4_destination_address, &buf[dhcp4_offset], dhcp4_length); return dhcp4_offset + dhcp4_length; } void interface_send(int sock, int interface_index, void * buf, int length, uint8_t const * eth_destination_address) { struct sockaddr_ll socket_address; socket_address.sll_ifindex = interface_index; socket_address.sll_halen = ETH_ALEN; memcpy(socket_address.sll_addr, eth_destination_address, 6); int flags = 0; int sret = sendto(sock, buf, length, flags, (struct sockaddr *)&socket_address, sizeof(struct sockaddr_ll)); if (sret < 0) { perror("sendto"); exit(EXIT_FAILURE); } } void attach_dhcp_filter(int sock) { struct sock_filter filter[] = { { 0x28, 0, 0, 0x0000000c }, { 0x15, 0, 8, 0x00000800 }, { 0x30, 0, 0, 0x00000017 }, { 0x15, 0, 6, 0x00000011 }, { 0x28, 0, 0, 0x00000014 }, { 0x45, 4, 0, 0x00001fff }, { 0xb1, 0, 0, 0x0000000e }, { 0x48, 0, 0, 0x00000010 }, { 0x15, 0, 1, 0x00000044 }, { 0x06, 0, 0, 0x00040000 }, { 0x06, 0, 0, 0000000000 }, }; struct sock_fprog fprog = { .len = sizeof(filter) / sizeof(filter[0]), .filter = filter, }; int ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, (sizeof (fprog))); if (ret < 0) { perror("setsockopt(SO_ATTACH_FILTER)"); exit(EXIT_FAILURE); } } int main() { srand(time(NULL)); uint8_t buf[16384]; ////////////////////////////////////////////////////////////////////// // socket ////////////////////////////////////////////////////////////////////// int s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); if (s < 0) { perror("socket"); exit(EXIT_FAILURE); } { int enable = 1; int ret = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &enable, (sizeof (int))); if (ret < 0) { perror("setsockopt(SO_BROADCAST)"); exit(EXIT_FAILURE); } } ////////////////////////////////////////////////////////////////////// // interface index ////////////////////////////////////////////////////////////////////// char const * interface_name = "wlp174s0"; struct ifreq if_index; memset(&if_index, 0, (sizeof (struct ifreq))); strncpy(if_index.ifr_name, interface_name, IFNAMSIZ - 1); int iret = ioctl(s, SIOCGIFINDEX, &if_index); if (iret < 0) { perror("ioctl(SIOCGIFINDEX)"); exit(EXIT_FAILURE); } printf("interface index %d\n", if_index.ifr_ifindex); ////////////////////////////////////////////////////////////////////// // interface address ////////////////////////////////////////////////////////////////////// struct ifreq if_hwaddr; memset(&if_hwaddr, 0, sizeof(struct ifreq)); strncpy(if_hwaddr.ifr_name, interface_name, IFNAMSIZ - 1); int hret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr); if (hret < 0) { perror("ioctl(SIOCGIFHWADDR)"); exit(EXIT_FAILURE); } printf("hardware address %02x:%02x:%02x:%02x:%02x:%02x\n", (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[0], (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[1], (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[2], (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[3], (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[4], (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[5]); ////////////////////////////////////////////////////////////////////// // bind ////////////////////////////////////////////////////////////////////// struct sockaddr_ll bind_addr = { .sll_family = AF_PACKET, .sll_protocol = htons(ETH_P_ALL), .sll_ifindex = if_index.ifr_ifindex, }; int bret = bind(s, (struct sockaddr *)&bind_addr, (sizeof (struct sockaddr_ll))); if (bret < 0) { perror("bind"); exit(EXIT_FAILURE); } attach_dhcp_filter(s); ////////////////////////////////////////////////////////////////////// // send ////////////////////////////////////////////////////////////////////// uint32_t dhcp_transaction_id = rand(); uint8_t eth_source_address[6] = {}; memcpy(eth_source_address, if_hwaddr.ifr_hwaddr.sa_data, 6); uint8_t eth_destination_address[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; uint32_t ipv4_source_address = 0x00000000; uint32_t ipv4_destination_address = 0xffffffff; int length = make_packet(buf, eth_source_address, eth_destination_address, ipv4_source_address, ipv4_destination_address, dhcp_transaction_id, dhcp4::message_type::dhcpdiscover); interface_send(s, if_index.ifr_ifindex, buf, length, eth_destination_address); uint8_t recvbuf[65536]; struct sockaddr_ll recv_address; int flags = 0; socklen_t socklen = (sizeof (struct sockaddr_ll)); ssize_t ret = recvfrom(s, recvbuf, 16384, flags, (struct sockaddr *)&recv_address, &socklen); printf("recv ret %ld\n", ret); close(s); exit(EXIT_SUCCESS); }