This example shows how to query and update Domain Name System (DNS) records.
/**************************************************************************/ /* 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; }