LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 11-27-2012, 09:07 PM   #1
prushik
Member
 
Registered: Mar 2009
Location: South Korea
Distribution: Lubuntu, BetterLinux
Posts: 364

Rep: Reputation: 28
Writing a simple DHCP server (for Linux)


Hi guys, I'm working on writing a DHCP server following RFC2131. So far, RFC2131 is the most difficult RFC I have read. If you just want a basic idea of how the exchange works and not read all the crap in RFC2131, you can read RFC951 (BOOTP) since its basically the same thing.
Anyways, the idea is that the client broadcasts a message asking for an IP address. My server successfully receives the packet and understands it. Then the server has to send a packet back to the client.
Now, according to both RFC documents, the server can simply send the response packet back out to the broadcast address on port 68. This is where I run into trouble. The client sends a the request packet out from 67 to 68, so I figured I could just send one right back over the same socket, but this didn't work. So I manually set up a broadcast socket, and guess what, that doesn't work either.
According to wireshark (running on the server) the broadcast from the server never goes out, however, if I send the broadcast out on port 67 instead, then my server successfully picks up the packet it just sent out. No error is reported in any case, its as if the packet gets sent, but the client just never gets it.
The client I am using is an IPtime wired router (WAN port). I tried my girlfriend's laptop as a client, but the lights on the ethernet port didn't light up, and her machine is Windows and all in Chinese (which I can't read) so I gave up on that. I guess what I need is a crossover cable to make that work, although I swear I have shared internet to her computer before... That's another issue.
What I want to know is why doesn't the packet get to the client??
Here is what my code looks like:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

struct dhcp_packet
{
	unsigned char OP,HTYPE,HLEN,HOPS;
	uint32_t XID;
	uint16_t SECS, FLAGS;
	unsigned char CIADDR[4];
	unsigned char YIADDR[4];
	unsigned char SIADDR[4];
	unsigned char GIADDR[4];
	unsigned char CHADDR[16];
	unsigned char SNAME[64];
	unsigned char FILE[128];
	unsigned char OPTIONS[312];
};

struct bootp_packet
{
	unsigned char OP,HTYPE,HLEN,HOPS;
	uint32_t XID;
	uint16_t SECS, VOID;
	unsigned char CIADDR[4];
	unsigned char YIADDR[4];
	unsigned char SIADDR[4];
	unsigned char GIADDR[4];
	unsigned char CHADDR[16];
	unsigned char SNAME[64];
	unsigned char FILE[128];
	unsigned char VEND[64];
};

void error(unsigned char *msg)
{
	perror(msg);
	exit(1);
}

struct dhcp_packet * parse_dhcp_packet(unsigned char * data, int n)
{
//DHCP PACKET FORMAT
//	Octet	Description
//	1	OP
//	2	HTYPE
//	3	HLEN
//	4	HOPS
//	5-8	XID
//	9,10	SECS
//	11,12	FLAGS
//	13-16	CIADDR
//	17-20	YIADDR
//	21-24	SIADDR
//	25-28	GIADDR
//	29-44	CHADDR
//	45-108	SNAME
//	109-236	FILE
//	237-576	OPTIONS
	struct dhcp_packet *packet;
	packet = malloc(sizeof(struct dhcp_packet));

	return packet;
}


int main(int argc, unsigned char *argv[])
{
	int sockfd, clilen;
	unsigned char buffer[576], *data;
	struct sockaddr_in serv_addr, cli_addr;
	int n;

	printf("struct size: %d\n",sizeof(struct dhcp_packet));

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0)
		error("Error opening socket");

	int broadcastEnable=1;
	int ret=setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));

	memset(&serv_addr, 0, sizeof(serv_addr));

	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = INADDR_ANY;
	serv_addr.sin_port = htons(67);	//DHCP uses port 67 for server and 68 for client
	if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
		error("Error binding");
	clilen = sizeof(cli_addr);
	while (1)
	{
		struct dhcp_packet packet;
		memset(&packet, 0, sizeof(struct dhcp_packet));
		n = recvfrom(sockfd,&packet,sizeof(struct dhcp_packet),0,(struct sockaddr *) &cli_addr,&clilen);
		if (n <= 0)
			error("Error receiving");

		printf("|%4d|%3d|%3d|%4d|\n",packet.OP,packet.HTYPE,packet.HLEN,packet.HOPS);
		printf("|%17X|\n|%8hd|%8hd|\n",packet.XID,packet.SECS,packet.FLAGS);
		printf("|%5d.%3d.%3d.%3d|\n",packet.CIADDR[0],packet.CIADDR[1],packet.CIADDR[2],packet.CIADDR[3]);
		printf("|%5d.%3d.%3d.%3d|\n",packet.YIADDR[0],packet.YIADDR[1],packet.YIADDR[2],packet.YIADDR[3]);
		printf("|%5d.%3d.%3d.%3d|\n",packet.SIADDR[0],packet.SIADDR[1],packet.SIADDR[2],packet.SIADDR[3]);
		printf("|%5d.%3d.%3d.%3d|\n",packet.GIADDR[0],packet.GIADDR[1],packet.GIADDR[2],packet.GIADDR[3]);
		printf("|%2X:%2X:%2X:%2X:%2X:%2X|\n",packet.CHADDR[0],packet.CHADDR[1],packet.CHADDR[2],packet.CHADDR[3],packet.CHADDR[4],packet.CHADDR[5]);

		packet.OP=2;
		packet.HOPS++;
		packet.FLAGS=1;
		packet.YIADDR[0]=192; packet.YIADDR[1]=168; packet.YIADDR[2]=14; packet.YIADDR[3]=99;
		packet.SIADDR[0]=192; packet.SIADDR[1]=168; packet.SIADDR[2]=14; packet.SIADDR[3]=14;
//		packet.GIADDR[0]=192; packet.GIADDR[1]=168; packet.GIADDR[2]=14; packet.GIADDR[3]=14;

		memset(&cli_addr, 0, sizeof(cli_addr));
		cli_addr.sin_family = AF_INET;
		cli_addr.sin_port = (in_port_t)htons(68);
		cli_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
		
		n = sendto(sockfd,&packet,sizeof(struct dhcp_packet),0,(struct sockaddr *) &cli_addr,clilen);

		if (n <= 0)
			error("Error sending");
		}

	return 0;
}
Note that some of it is never used.



EDIT: UPDATE - I tried capturing on wiresharks "any" device (capture on all interfaces) and I see the packets which get sent out if I remove the broadcast code. For some reason they get sent from 127.0.0.1 to 127.0.0.1, I have no idea why that happens, the inbound packets clearly come from 0.0.0.0 to 255.255.255.255
Also, I built a new kernel and now broadcasts from my software fail with the error: network unreachable However, don't worry about this too much unless this info helps solve my issue, I had some trouble with some patches patches I applied to the kernel as well as some 3rd party drivers I built, as a result I screwed up my kernel .config so this new kernel has some issues.

Last edited by prushik; 11-29-2012 at 05:39 AM.
 
  


Reply

Tags
bootp, dhcp, dhcp server, rfc2131


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Writing Simple Device Driver In Linux i_love_linux Linux - Kernel 6 09-04-2007 07:16 PM
Help with getting a simple dhcp server working GUIPenguin Linux - Networking 2 02-09-2006 07:06 AM
Linux Noob writing simple application that needs to query SQLServer radikaled Linux - Newbie 1 01-18-2005 11:26 AM
Simple Debian Router including a DHCP Server stormblast Debian 20 09-22-2004 05:11 AM
writing a simple file system in linux Deepthi_57 Linux - Newbie 1 05-03-2004 12:42 AM


All times are GMT -5. The time now is 04:06 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration