Skip to content
This repository was archived by the owner on Aug 23, 2022. It is now read-only.

Commit

Permalink
Initial Import
Browse files Browse the repository at this point in the history
  • Loading branch information
pierresy committed Dec 4, 2014
0 parents commit 989c165
Show file tree
Hide file tree
Showing 6 changed files with 488 additions and 0 deletions.
22 changes: 22 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Cflag=
LDflag=

all: dhclient

dhclient: dhclient.o dhcp.o net.o
gcc $(LDflag) dhclient.o dhcp.o net.o -o dhclient

dhclient.o: dhclient.c
gcc $(Cflag) -c dhclient.c

dhcp.o: dhcp.c dhcp.h
gcc $(Cflag) -c dhcp.c

net.o: net.c net.h
gcc $(Cflag) -c net.c

clean:
rm -f *.o

cleanall: clean
rm -f dhclient
157 changes: 157 additions & 0 deletions dhclient.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#include "dhcp.h"
#include "net.h"

#include <sys/socket.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <net/ethernet.h>

#include <linux/if_arp.h>

#define BUFF_SIZE 1024

//http://aschauf.landshut.org/fh/linux/udp_vs_raw/ch01s03.html

void main(int argc, char** argv)
{
if(geteuid() != 0)
{
fprintf(stderr, "You need root permissions\n");
exit(1);
}

//TODO : Add a debug mode
char* interface;
if(argc > 1)
interface = argv[1];
else
{
fprintf(stderr, "Please specify network interface to use\n");
exit(1);
}

// printf("Interface = %s\n", interface);

int sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));

//Set receive timeout
struct timeval tv;
tv.tv_usec = 0;
tv.tv_sec = 10; //10 seconds in case of latency on the network
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

//retrieve ethernet NIC index and HW address
struct hw_eth_iface iface = find_iface(sock, interface); // TODO : Check interface existency, and print a list of possible NIC

struct sockaddr_ll target;
memset(&target, 0, sizeof(target));
target.sll_family = PF_PACKET;
target.sll_protocol = htons(ETH_P_IP);
target.sll_ifindex = iface.index;
target.sll_hatype = ARPHRD_ETHER;
target.sll_pkttype = PACKET_HOST;
target.sll_halen = ETH_ALEN;

memset(target.sll_addr, 0xff, 6);

char buffer[BUFF_SIZE];

// struct dhcp_pkt *dhcp = (struct dhcp_pkt*)(buffer + sizeof(struct udpheader) + sizeof(struct ipheader));
struct dhcp_pkt dhcp;
int dhcp_len = build_dhcp_discover(&dhcp, iface.hw_addr, iface.addr_len);

int len = build_ip4_udp_pkt(buffer, BUFF_SIZE, (unsigned char*)&dhcp, dhcp_len, "0.0.0.0", "255.255.255.255", 68, 67, IPPROTO_UDP);

//Send the packet over the network
if(sendto(sock, buffer, len, 0, (struct sockaddr *)&target, sizeof(target)) < 0)
{
perror("Error while writing to socket");
exit(1);
}

//Now, wait for the server response, and read it

receive:
memset(buffer, 0, BUFF_SIZE);

//Read a packet
int read_len = recvfrom(sock, buffer, BUFF_SIZE, 0, NULL, NULL);
if(read_len <= 0)
{
perror("Cannot read");
exit(1);
}

struct ipheader *rip = (struct ipheader*) buffer;
struct udpheader *rudp = (struct udpheader*)(buffer + sizeof(struct ipheader));
struct dhcp_pkt *rdhcp = (struct dhcp_pkt*)(buffer + sizeof(struct udpheader) + sizeof(struct ipheader));

//Check packet validity
// if dest port isn't our or packet is not a dhcp one, drop the packet
if(rip->iph_protocol != IPPROTO_UDP || rudp->udph_destport != htons(68) || !is_dhcp(rdhcp) || rdhcp->op != OP_BOOT_REPLY)
goto receive;

// printf("Data Recieved, length = %d\n", read_len);

//Find the IP attributed to us by the server
struct in_addr raddr;
raddr.s_addr = rdhcp->yi_addr;

printf("IPADDR=%s\n", inet_ntoa(raddr));

//Now check DHCP options, and process them
struct dhcp_opt *opt = NULL;
int offs = 0;
opt = get_dhcp_option(rdhcp, &offs);
while(opt != NULL)
{
// printf("OPT FOUND offset = %d\n", offs);
switch(opt->id)
{
case OPTION_ROUTER: // If the option is the gateway address
if(opt->len == 4)
{
raddr.s_addr = char_to_ip(opt->values);
printf("GATEWAY=%s\n", inet_ntoa(raddr));
}
break;

case OPTION_SUBNET_MASK: // If the option is the netwmask
if(opt->len == 4)
{
raddr.s_addr = char_to_ip(opt->values);
printf("NETMASK=%s\n", inet_ntoa(raddr));
}
break;

case OPTION_DNS: // If option is the DNS addresses
if(opt->len % 4 == 0)
{
int i = 0;
printf("NAMESERVER=");
int max = opt->len / 4;
for(i = 0; i < max; i++)
{
raddr.s_addr = char_to_ip(opt->values + 4*i);
printf("%s", inet_ntoa(raddr));
if(i < max - 1)
printf(",");
}
printf("\n");
}
break;

default:
break;
}
opt = get_dhcp_option(rdhcp, &offs);
}

close(sock);
exit(0);
}
72 changes: 72 additions & 0 deletions dhcp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include "dhcp.h"

#include <stdlib.h>
#include <string.h>

int build_dhcp_discover(struct dhcp_pkt* pkt, unsigned char* src_mac, int mac_len)
{
memset(pkt, 0, sizeof(struct dhcp_pkt));
pkt->op = OP_BOOT_REQUEST;
pkt->htype = HW_TYPE_ETHERNET;
pkt->hlen = HW_LENGTH_ETHERNET;
pkt->hops = 0x00;
pkt->xid = 0x3903f326; //TODO: Random transaction ID
pkt->secs = 0x0000;
pkt->flags = 0x0000;
pkt->ci_addr = 0x00000000;
pkt->yi_addr = 0x00000000;
pkt->si_addr = 0x00000000;
pkt->gi_addr = 0x00000000;

// memcpy(pkt->cm_addr, src_mac, mac_len); // LINK problem
int i;
for(i = 0; i < mac_len; i++)
pkt->cm_addr[i] = src_mac[i];

pkt->magic = DHCP_MAGIC;

//Add DHCP options
pkt->opt[0] = OPTION_DHCP_MESSAGE_TYPE;
pkt->opt[1] = 0x01;
pkt->opt[2] = VALUE_MESSAGE_DISCOVER;

pkt->opt[3] = OPTION_PARAMETER_REQUEST_LIST;
pkt->opt[4] = 0x03;
pkt->opt[5] = OPTION_ROUTER; // Ask for gateway address
pkt->opt[6] = OPTION_SUBNET_MASK; // Ask for the netmask
pkt->opt[7] = OPTION_DNS; // ASK for DNS address

pkt->opt[8] = DHCP_END;


//TODO : Use the same procedure to write options, than the one used to read options
// pkt->opt[0].id = 53;
// pkt->opt[0].len = 0x01;
// pkt->opt[0].values[0] = 0x01;
//
// pkt->opt[1].id = DHCP_END;

return sizeof(struct dhcp_pkt);
}

int is_dhcp(struct dhcp_pkt* pkt)
{
// It's a DHCP packet if dhcp magic number is good
//TODO: check the packet length ?
return pkt->magic == DHCP_MAGIC;
}

struct dhcp_opt* get_dhcp_option(struct dhcp_pkt *pkt, int *offset)
{
if(pkt->opt[*offset] == 0x00 || pkt->opt[*offset] == DHCP_END)
return NULL;
// If the opt != end or != empty, cast the memory zone into a option struct, and return it
struct dhcp_opt* opt = (struct dhcp_opt*)&(pkt->opt[*offset]);
*offset += sizeof(struct dhcp_opt) + opt->len;
return opt;
}

unsigned int char_to_ip(unsigned char* ip)
{
return htonl(ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3]);
}
96 changes: 96 additions & 0 deletions dhcp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#ifndef _DHCP_H
#define _DHCP_H

#define DHCP_MAGIC htonl(0x63825363)

#define DHCP_MIN_PACK_SIZE 240

#define OP_BOOT_REQUEST 0x01
#define OP_BOOT_REPLY 0x02

#define HW_TYPE_ETHERNET 0x01
#define HW_LENGTH_ETHERNET 0x06

//DHCP options

#define DHCP_END 0xff

#define OPTION_DHCP_MESSAGE_TYPE 53
#define VALUE_MESSAGE_DISCOVER 0x01
#define VALUE_MESSAGE_OFFER 0x02
#define VALUE_MESSAGE_REQUEST 0x01
#define VALUE_MESSAGE_ACK 0x05
#define VALUE_MESSAGE_NAK 0x06
#define VALUE_MESSAGE_INFORM 0x08

#define OPTION_SERVER_IP 54
#define OPTION_LEASE_TIME 51
#define OPTION_REQUESTED_IP 50

#define OPTION_PARAMETER_REQUEST_LIST 55

#define OPTION_SUBNET_MASK 1
#define OPTION_ROUTER 3
#define OPTION_BROADCAST_ADDR 28
#define OPTION_DNS 6
#define OPTION_DOMAIN_NAME 15
#define OPTION_HOST_NAME 12

//These should not really be usefull for what we do
#define OPTION_TIME_OFFSET 2
#define OPTION_STATIC_ROUTE 121
#define OPTION_NIS_DOMAIN 40
#define OPTION_NIS_SERVERS 41
#define OPTION_NTP_SERVERS 42
#define OPTION_MTU 26
#define OPTION_DOMAIN_SEARCH 119

//DHCP options
struct dhcp_opt {
unsigned char id; // Option ID
unsigned char len; // Option value length
unsigned char values[]; // Option value(s)
};

//DHCP packet structure
struct dhcp_pkt
{
unsigned char op; // Message type
unsigned char htype; // HW type
unsigned char hlen; // HW addr length
unsigned char hops; // Hops

unsigned int xid; // Transaction ID

unsigned short secs; // seconds elapsed
unsigned short flags; // Bootp flags

unsigned int ci_addr; // Client address
unsigned int yi_addr; // Your address
unsigned int si_addr; // Next Server IP address
unsigned int gi_addr; // Relay agent IP address
unsigned char cm_addr[6]; // Client MAC address
unsigned char ch_addr[10]; // Client hardware address padding

unsigned char unused[192];

unsigned int magic; // DHCP magic number

unsigned char opt[128]; // Options padding
// struct dhcp_opt opt [64];
};

//Build a discover DHCP packet, return packet size
int build_dhcp_discover(struct dhcp_pkt* pkt, unsigned char* src_mac, int mac_len);

//Check if the packet is a DHCP one
int is_dhcp(struct dhcp_pkt* pkt);

//Find an option in the DHCP packet. offset is the position of the option in the packet.
// After the call, offset is updated to the offset of the next option (if any)
struct dhcp_opt* get_dhcp_option(struct dhcp_pkt *pkt, int *offset);

//Read an IP in a 4 bytes data array
unsigned int char_to_ip(unsigned char* ip);

#endif
Loading

0 comments on commit 989c165

Please sign in to comment.