Domain Name Service

From Nutwiki
Jump to: navigation, search

Overview

This example demonstrates how to configure the DNS settings of Nut/OS and retrieve DNS and MX records for a list of servers.

Please note that the NutDnsGetMxByDomain() currently seems to be broken as it returns bogus data that is definitely not valid. It is included for completeness of this example only. If you find NutDnsGetMxByDomain() to be working in future versions of Nut/OS, please remove this remark and update the output below.

Source Code

<source lang="c">

  1. include <dev/board.h>
  1. include <arpa/inet.h>
  2. include <net/route.h>
  3. include <pro/dhcp.h>
  1. include <stdlib.h>
  2. include <stdio.h>
  3. include <io.h>
  4. include <string.h>
  5. include <time.h>
  1. define LOCAL_IP "192.168.192.111"
  2. define GATE_IP "192.168.192.1"
  3. define DNS_IP "192.168.192.1"

const prog_char *server[3] = { "egnite.de", "google.com", "ethernut.de" };

int main(void) {

   unsigned long baud = 115200;
   uint32_t return_addr = 0;
   uint32_t return_mx = 0;
   int i = 0;
   NutRegisterDevice(&DEV_DEBUG, 0, 0);
   freopen(DEV_DEBUG_NAME, "w", stdout);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
   NutRegisterDevice(&DEV_ETHER, 0, 0);
   if (NutDhcpIfConfig(DEV_ETHER_NAME, 0, 60000)) {
       puts("Error: Cannot configure network.");
   }
   puts("DNS example\n");
   NutDnsConfig2(0, 0, inet_addr(DNS_IP), inet_addr(DNS_IP));
   NutIpRouteAdd(inet_addr(LOCAL_IP), 24, inet_addr(GATE_IP), &DEV_ETHER);
   for (i = 0; i < 3; i++) {
       return_addr = NutDnsGetHostByName(server[i]);
       return_mx = NutDnsGetMxByDomain(server[i]);
       printf("Host was: %s\n\tIP: %s\n\tMX: %s\n", server[i]);
       printf("\tIP: %s\n", inet_ntoa(return_addr)); 
       printf("\tMX: %s\n", inet_ntoa(return_mx));
   }
   for (;;);

} </source>

Details

<source lang="c">

  1. define LOCAL_IP "192.168.192.111"
  2. define GATE_IP "192.168.192.1"
  3. define DNS_IP "192.168.192.1"

const prog_char *server[3] = { "egnite.de", "google.com", "ethernut.de" }; </source>

First thing we do is define the LOCAL_IP (our board's IP), the GATE_IP (gateway IP, usually your router or the computer that provides the internet connection for your board) and DNS_IP (usually the router, too, but you may wish to use a different DNS server so we define it independently).

Next we declare a list of domain names we want to look up. The prog_char* data type is technically the same as a normal char* data type, except that it is stored in program space and thus doesn't waste RAM but only inflates the binary image by a few bytes. Unlike defines we can even declare arrays this way which will make our task way easier later on.

<source lang="c"> int main(void) {

   unsigned long baud = 115200;
   uint32_t return_addr = 0;
   uint32_t return_mx = 0;
   int i = 0;
   NutRegisterDevice(&DEV_DEBUG, 0, 0);
   freopen(DEV_DEBUG_NAME, "w", stdout);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
   NutRegisterDevice(&DEV_ETHER, 0, 0);
   if (NutDhcpIfConfig(DEV_ETHER_NAME, 0, 60000)) {
       puts("Error: Cannot configure network.");
   }
   puts("DNS example\n");

</source>

We set up the debug device, declare a variable to hold one returned IP and one returned MX record and output a banner. For more info on network configuration see the corresponding examples.

<source lang="c"> NutDnsConfig2(0, 0, inet_addr(DNS_IP), inet_addr(DNS_IP)); NutIpRouteAdd(inet_addr(LOCAL_IP), 24, inet_addr(GATE_IP), &DEV_ETHER); </source>

Now we configure the DNS settings of the board. 0 means "default hostname" and "default domain" respectively, the next two parameters are 2 DNS servers. The inet_addr call makes a numeric representation of our IP. It was stored as string, remember? Strings don't make for good number crunching and IPs are numbers anyway. It is common practice to pass 2 DNS servers, one for normal use and one as fallback, if the first doesn't work or is unable to process certain requests. We pass the same server twice to keep it simple.

The next line adds an IP route, telling Nut/OS which requests to handle via which Gateway. Here we assign our gateway to make sure we're able to contact "the web". The second parameter may look a little confusing if you're not used to netmasks. We want the board to work in the subnet "255.255.255.0". A short way of writing netmasks is simply saying "the first x bit are 1, the rest is 0. This is exactly what we do here. The first 24 bit are 1, the last 8 are 0, resulting in "255.255.255.0".

<source lang="c"> for (i = 0; i < 3; i++) {

   return_addr = NutDnsGetHostByName(server[i]);
   return_mx = NutDnsGetMxByDomain(server[i]);
   printf("Host was: %s\n\tIP: %s\n\tMX: %s\n", server[i]);
   printf("\tIP: %s\n", inet_ntoa(return_addr)); 
   printf("\tMX: %s\n", inet_ntoa(return_mx));

} </source>

After all this setting up the actual DNS request is quite simple. A call to NutDnsGetHostByName - and NutDnsGetMxByDomain respectively - returns a numeric IP representation which we store in our variables. This call may block for a moment so don't worry if your program needs a moment to output something.

Now we output the hostname used and then our 2 retrieved records. Did you notice the strange strdup? Great. inet_ntoa is a function that turns our numeric IP into a string which looks like an IP that we're used to. Here's the catch: inet_ntoa is not threadsafe, meaning that if another thread was to call inet_ntoa, it would replace the result of the last call. This would make us output a totally wrong address so we duplicate the returned string to another RAM area first. In this example this is not needed since it is not multithreaded anyway, it's just included to make sure you are aware of this when starting your own application.

Output

<source lang="text"> DNS example

Host was: egnite.de

       IP: 88.198.132.201
       MX: 0.10.192.12

Host was: google.com

       IP: 74.125.127.100
       MX: 0.0.0.0

Host was: ethernut.de

       IP: 88.198.132.203
       MX: 0.10.192.12

</source>

See also





Template:Languages