summary refs log tree commit diff
path: root/dhcp_probe.c
diff options
context:
space:
mode:
Diffstat (limited to 'dhcp_probe.c')
-rw-r--r--dhcp_probe.c250
1 files changed, 250 insertions, 0 deletions
diff --git a/dhcp_probe.c b/dhcp_probe.c
new file mode 100644
index 0000000..03bde74
--- /dev/null
+++ b/dhcp_probe.c
@@ -0,0 +1,250 @@
+#include<stdio.h>
+#include<ctype.h>
+#include<stdlib.h>
+#include<string.h>
+#include<unistd.h>
+#include<signal.h>
+#include<sys/wait.h>
+#include<sys/types.h>
+#include<sys/socket.h>
+#include<netinet/in.h>
+#include<arpa/inet.h>
+#include<errno.h>
+#include<sys/file.h>
+#include<sys/msg.h>
+#include<sys/ipc.h>
+#include<time.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <getopt.h>
+
+//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);
+}