This repository was archived by the owner on Aug 23, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
pierresy
committed
Dec 4, 2014
0 parents
commit 989c165
Showing
6 changed files
with
488 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.