Example: Update and query DNS

This example shows how to query and update Domain Name System (DNS) records.

Note: By using the code examples, you agree to the terms of the Code license and disclaimer information.
/**************************************************************************/
/* This program updates a DNS using a transaction signature (TSIG) to     */
/* sign the update packet.  It then queries the DNS to verify success.    */
/**************************************************************************/

/**************************************************************************/
/* Header files needed for this sample program                            */
/**************************************************************************/
#include <stdio.h>
#include <errno.h>
#include <arpa/inet.h>
#include <resolv.h>
#include <netdb.h>

/**************************************************************************/
/* Declare update records - a zone record, a pre-requisite record, and    */
/* 2 update records                                                       */
/**************************************************************************/
ns_updrec update_records[] =
{
   {
      {NULL,&update_records[1]},
      {NULL,&update_records[1]},
      ns_s_zn,                  /* a zone record */
      "mydomain.ibm.com.",
      ns_c_in,
      ns_t_soa,
      0,
      NULL,
      0,
      0,
      NULL,
      NULL,
      0
   },
   {
      {&update_records[0],&update_records[2]},
      {&update_records[0],&update_records[2]},
      ns_s_pr,                 /* pre-req record */
      "mypc.mydomain.ibm.com.",
      ns_c_in,
      ns_t_a,
      0,
      NULL,
      0,
      ns_r_nxdomain,    /* record must not exist */
      NULL,
      NULL,
      0
   },
   {
      {&update_records[1],&update_records[3]},
      {&update_records[1],&update_records[3]},
      ns_s_ud,                  /* update record */
      "mypc.mydomain.ibm.com.",
      ns_c_in,
      ns_t_a,                   /* IPv4 address  */
      10,
      (unsigned char *)"10.10.10.10",
      11,
      ns_uop_add,                /* to be added  */
      NULL,
      NULL,
      0
   },
   {
      {&update_records[2],NULL},
      {&update_records[2],NULL},
      ns_s_ud,                  /* update record */
      "mypc.mydomain.ibm.com.",
      ns_c_in,
      ns_t_aaaa,                /* IPv6 address  */
      10,
      (unsigned char *)"fedc:ba98:7654:3210:fedc:ba98:7654:3210",
      39,
      ns_uop_add,                /* to be added  */
      NULL,
      NULL,
      0
   }
};

/**************************************************************************/
/* These two structures define a key and secret that must match the one   */
/* configured on the DNS :                                                */
/*   allow-update {                                                       */
/*   key my-long-key.;                                                    */
/*   }                                                                    */
/*                                                                        */
/* This must be the binary equivalent of the base64 secret for            */
/* the key                                                                */
/**************************************************************************/
unsigned char secret[18] =
{
   0x6E,0x86,0xDC,0x7A,0xB9,0xE8,0x86,0x8B,0xAA,
   0x96,0x89,0xE1,0x91,0xEC,0xB3,0xD7,0x6D,0xF8
};

ns_tsig_key my_key = {
   "my-long-key",            /* This key must exist on the DNS */
   NS_TSIG_ALG_HMAC_MD5,
   secret,
   sizeof(secret)
};

void main()
{
   /***********************************************************************/
   /* Variable and structure definitions.                                 */
   /***********************************************************************/
   struct state res;
   int result, update_size;
   unsigned char update_buffer[2048];
   unsigned char answer_buffer[2048];
   int buffer_length = sizeof(update_buffer);

   /* Turn off the init flags so that the structure will be initialized   */
   res.options &= ~ (RES_INIT | RES_XINIT);

   result = res_ninit(&res);

   /* Put processing here to check the result and handle errors           */

   /* Build an update buffer (packet to be sent) from the update records  */
   update_size = res_nmkupdate(&res, update_records,
                               update_buffer, buffer_length);

   /* Put processing here to check the result and handle errors           */

   {
      char zone_name[NS_MAXDNAME];
      size_t zone_name_size = sizeof zone_name;
      struct sockaddr_in s_address;
      struct in_addr addresses[1];
      int number_addresses = 1;

   /* Find the DNS server that is authoritative for the domain            */
   /* that we want to update                                              */

      result = res_findzonecut(&res, "mypc.mydomain.ibm.com", ns_c_in, 0,
      zone_name, zone_name_size,
                               addresses, number_addresses);

   /* Put processing here to check the result and handle errors           */

   /* Check if the DNS server found is one of our regular DNS addresses   */
      s_address.sin_addr = addresses[0];
      s_address.sin_family = res.nsaddr_list[0].sin_family;
      s_address.sin_port = res.nsaddr_list[0].sin_port;
      memset(s_address.sin_zero, 0x00, 8);

      result = res_nisourserver(&res, &s_address);

   /* Put processing here to check the result and handle errors           */

   /* Set the DNS address found with res_findzonecut into the res         */
   /* structure.  We will send the (TSIG signed) update to that DNS.      */
      res.nscount = 1;
      res.nsaddr_list[0] = s_address;

   /* Send a TSIG signed update to the DNS                                */
      result = res_nsendsigned(&res, update_buffer, update_size,
                               &my_key,
                               answer_buffer, sizeof answer_buffer);

   /* Put processing here to check the result and handle errors           */
   }

   /***********************************************************************/
   /* The res_findzonecut(), res_nmkupdate(), and res_nsendsigned()       */
   /* can be replaced with one call to res_nupdate() using              */
   /* update_records[1] to skip the zone record:                          */
   /*                                                                     */
   /* result = res_nupdate(&res, &update_records[1], &my_key);            */
   /*                                                                     */
   /***********************************************************************/
   /***********************************************************************/
   /* Now verify that our update actually worked!                         */
   /* We choose to use TCP and not UDP, so set the appropriate option now */
   /* that the res variable has been initialized. We also want to ignore  */
   /* the local cache and always send the query to the DNS server.        */
   /***********************************************************************/

   res.options |= RES_USEVC|RES_NOCACHE;

   /* Send a query for mypc.mydomain.ibm.com address records              */
   result = res_nquerydomain(&res,"mypc", "mydomain.ibm.com.",
                             ns_c_in, ns_t_a,
                             update_buffer, buffer_length);

   /* Sample error handling and printing errors                           */
   if (result == -1)
   {
      printf("\nquery domain failed.  result = %d \nerrno: %d: %s \
              \nh_errno: %d: %s",
             result,
            errno, strerror(errno),
             h_errno, hstrerror(h_errno));
   }
   /***********************************************************************/
   /* The output on a failure will be:                                    */
   /*                                                                     */
   /* query domain failed.  result = -1                                   */
   /* errno: 0: There is no error.                                        */
   /* h_errno: 5: Unknown host                                            */
   /***********************************************************************/
   return;
}
Related concepts
Thread safety
Related reference
Data caching