DHCP and DNS servers with Arduino

I have been working on my Arduino-based robot and wanted to have a way to run several devices on the same ad-hoc network and use their host names rather than their IP addresses.

It turned out that there was nothing available that worked out of the box. I tried several libraries, but some didn't have DNS server functionality, some were for the Ethernet library, which wasn't compatible with my shield (RedFly), and some simply didn't work.

First step was to get DHCP working. The sequence of DHCP messages is simple, but the format is not so much; it took me several attempts to get the format to be correct enough for the client to take the response. Wireshark was invaluable in showing the messages and giving me the ability to compare correct messages from the DHCP server in my router with the (initially) incorrect messages from my DHCP server.

Here is how the sequence of messages looks in Wireshark (this is between Windows Vista as a client and my DHCP server implementation running on Arduino + RedFly):

Note that you can use "bootp" filter to select DHCP and BOOTP related messages. The Windows client sends DHCP Request message, which gets DHCP NAK in response as the server doesn't have any record of the client's mac address in its table (assuming this is a fresh restart of the server). The client then sends DHCP Discover message, which gets DHCP Offer response (the server offered to extend a lease). The client then sends DHCP Request, which now gets DHCP ACK as the server already registered the client in its lease table and confirms the lease.

This is the final confirmation message in this session:

At this point the client gets its DHCP address and can ping the server (in this case Arduino, which has 192.168.2.1 address).

Now the DNS server comes into play. If you enter "arduino" into the browser the client (or rather its DNS resolver) will try to resolve this name by sending queries to the registered DNS servers (or by using other means like mDNS and LLMNR). This interaction can be seen if you filter captured packets in Wireshark by "dns" or port number "udp.port == 53":

As can be seen in the screenshot, the client sent a query about "arduino.mshome.net" (in this case "mshome.net" is configured as the domain name, which was returned in the DHCP response as option 15); the server responds with the IP address for this hostname (192.168.2.1). Note that the server responded with "No such name" response to queries about other domains as it had no information and no access to other DNS servers to forward the request to.

The client then sends an HTTP request to that address and gets a simple HTTP response back:

Here is how you'd use this library:

#include <DHCPLite.h>
...
      // for a request that comes to port DHCP_SERVER_PORT (UDP/67)
      buf_len = DHCPreply((RIP_MSG*)buf, buf_len, serverIP, domainName); 
...
      // for a request that comes to port DNS_SERVER_PORT (UDP/53 or TCP/53)
      buf_len = DNSreply((DNS_MSG*)buf, buf_len, serverIP, serverName); 

Both DHCPreply and DNSreply methods use the buffer that has the received message to compile a return message; they both return a new message length or 0 to indicate a problem with the received message.

The code for this library is available here. Give it a try and leave a comment or send me an email if you see a problem.

Leave a comment

what will you say?
(required)
(required)

About

I am Paul Kulchenko.
I live in Kirkland, WA with my wife and three kids.
I do consulting as a software developer.
I study robotics and artificial intelligence.
I write books and open-source software.
I teach introductory computer science.
I develop a slick Lua IDE and debugger.

Recommended

Close