#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //TODO: Name DHCPPROBE' #define BROADCAST_ADDRESS "255.255.255.255" #define MAX_DHCP_CHADDR_LENGTH 16 #define MAX_DHCP_SNAME_LENGTH 64 #define MAX_DHCP_FILE_LENGTH 128 #define DHCP_MAGIC_LENGTH 4 #define MAX_DHCP_OPTIONS_LENGTH 312 - DHCP_MAGIC_LENGTH typedef struct dhcp_packet { uint8_t op; uint8_t htype; uint8_t hlen; uint8_t hops; uint32_t xid; uint16_t secs; uint16_t flags; uint32_t ciaddr; uint32_t yiaddr; uint32_t siaddr; uint32_t giaddr; uint8_t chaddr[MAX_DHCP_CHADDR_LENGTH]; uint8_t sname[MAX_DHCP_SNAME_LENGTH]; uint8_t file[MAX_DHCP_FILE_LENGTH]; uint8_t magic[DHCP_MAGIC_LENGTH]; uint8_t opt[MAX_DHCP_OPTIONS_LENGTH]; } __attribute__((__packed__)) dhcp_packet_t; static int fill_mac_address(uint8_t* base_addr, const char* interface_name) { int fd; struct ifreq ifr; if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) exit(1); strcpy(ifr.ifr_name, interface_name); if(ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) exit(1); close(fd); memcpy(base_addr, ifr.ifr_addr.sa_data, 6); return 0; } static int construct_dhcp_discover(dhcp_packet_t* packet, const char* iface_name) { srand(time(NULL)); packet->op = 1; //request packet->htype = 6; //wifi packet->hlen = 6; //default packet->hops = 0; packet->xid = htonl(rand()); //random packet->secs = htons(0); packet->flags = htons(0x8000); //dont know my own ip, so send back by broadcast packet->ciaddr = 0; //my ip address packet->yiaddr = 0; //my future ip address packet->siaddr = 0; //server address packet->giaddr = 0; //gateway address if(fill_mac_address(packet->chaddr, iface_name) < 0) exit(1); packet->magic[0]=0x63; packet->magic[1]=0x82; packet->magic[2]=0x53; packet->magic[3]=0x63; packet->opt[0]=53; packet->opt[1]=1; packet->opt[2]=1; packet->opt[MAX_DHCP_OPTIONS_LENGTH - 1] = 0xFF; return 0; } static int handle_dhcp_option(uint8_t option_type, const uint8_t* option_start, uint32_t option_length) { //printf("Option type: %d (length: %d)\n", option_type, option_length); // http://networksorcery.com/enp/protocol/bootp/options.htm switch(option_type) { case 1: //mask { printf("Mask: %u.%u.%u.%u\n", option_start[0], option_start[1], option_start[2], option_start[3]); break; } case 6: //dns { printf("DNS Server: %u.%u.%u.%u\n", option_start[0], option_start[1], option_start[2], option_start[3]); break; } case 15: //domain name { char domain_name[option_length + 1]; strncpy(domain_name, (const char*)option_start, option_length); domain_name[option_length] = '\0'; printf("Domain name: %s\n", domain_name); break; } case 54: //router { printf("DHCP server ip: %u.%u.%u.%u\n", option_start[0], option_start[1], option_start[2], option_start[3]); break; } default: //undefined return 0; //-1 } return 0; } static void print_dhcp_offer_info(const dhcp_packet_t* dhcp_offer) { //uint32_t ip = ntohl(dhcp_offer->yiaddr); //printf("Got IP %u.%u.%u.%u\n", ip >> 24, ((ip << 8) >> 24), (ip << 16) >> 24, (ip << 24) >> 24); size_t i = 0; while(i < MAX_DHCP_OPTIONS_LENGTH && dhcp_offer->opt[i] != 0) { uint8_t option = dhcp_offer->opt[i++]; uint32_t length = dhcp_offer->opt[i++]; if(handle_dhcp_option(option, &dhcp_offer->opt[i], length) < 0) exit(1); i += dhcp_offer->opt[length]; } } int main(int argc, char** argv) { const char* iface_name = NULL; char c; while((c = getopt(argc, argv, "i:")) > 0) { switch(c) { case 'i': iface_name = optarg; break; default: usage: printf("Usage: ./dhcpprobe -i %%INTERFACE\n"); exit(1); } } if(iface_name == NULL) goto usage; int sock_fd; printf("Creating socket...\n"); if((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) exit(1); else printf("Succesfully created socket.\n"); printf("Setting socket options...\n"); int broadcast_enabled = 1; if(setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, &broadcast_enabled, sizeof(int)) < 0) exit(1); else printf("Succesfully set socket options.\n"); printf("Binding... "); struct sockaddr_in server_send_addr = {0}; server_send_addr.sin_family = AF_INET; server_send_addr.sin_addr.s_addr = inet_addr(BROADCAST_ADDRESS); server_send_addr.sin_port = htons(67); if(bind(sock_fd, (struct sockaddr*)&server_send_addr, sizeof(struct sockaddr_in)) < 0) exit(1); else printf("Succesfully binded.\n"); printf("Sending dhcpdiscover...\n"); dhcp_packet_t dhcp_discover = {0}; construct_dhcp_discover(&dhcp_discover, iface_name); if(sendto(sock_fd, &dhcp_discover, sizeof(dhcp_packet_t), 0, (struct sockaddr*)&server_send_addr, sizeof(struct sockaddr_in)) == -1) exit(1); else printf("Succesfully sent dhcpdiscover.\n"); close(sock_fd); if((sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) exit(1); else printf("Opened socket to recieve response.\n"); if(setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, &broadcast_enabled, sizeof(int)) < 0) exit(1); else printf("Succesfully set socket options.\n"); struct sockaddr_in server_recv_addr = {0}; server_recv_addr.sin_family = AF_INET; server_recv_addr.sin_port = htons(68); server_recv_addr.sin_addr.s_addr = INADDR_ANY; if(bind(sock_fd, (struct sockaddr*)&server_recv_addr, sizeof(struct sockaddr_in)) < 0) exit(1); else printf("Succesfully binded.\n"); dhcp_packet_t dhcp_recv = {0}; recieve: if(recvfrom(sock_fd, &dhcp_recv, sizeof(dhcp_packet_t), 0, NULL, 0) < 0) exit(1); else if(dhcp_discover.xid != dhcp_recv.xid) { printf("Recieved invalid dhcp offer.\n"); goto recieve; } else printf("Succesfully recieved dhcp offer.\n"); print_dhcp_offer_info(&dhcp_recv); }