summaryrefslogtreecommitdiff
path: root/examples/ldns-update.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/ldns-update.c')
-rw-r--r--examples/ldns-update.c320
1 files changed, 320 insertions, 0 deletions
diff --git a/examples/ldns-update.c b/examples/ldns-update.c
new file mode 100644
index 0000000..c678203
--- /dev/null
+++ b/examples/ldns-update.c
@@ -0,0 +1,320 @@
+/* $Id: ldns-update.c,v 1.1 2005/09/13 09:37:05 ho Exp $ */
+/*
+ * Example of the update functionality
+ *
+ * See the file LICENSE for the license
+ */
+
+
+#include "config.h"
+
+#include <strings.h>
+#include <ldns/ldns.h>
+
+/* dynamic update stuff */
+static ldns_resolver *
+ldns_update_resolver_new(const char *fqdn, const char *zone,
+ ldns_rr_class class, uint16_t port, ldns_tsig_credentials *tsig_cred, ldns_rdf **zone_rdf)
+{
+ ldns_resolver *r1, *r2;
+ ldns_pkt *query = NULL, *resp = NULL;
+ ldns_rr_list *nslist, *iplist;
+ ldns_rdf *soa_zone, *soa_mname = NULL, *ns_name;
+ size_t i;
+ ldns_status s;
+
+ if (class == 0) {
+ class = LDNS_RR_CLASS_IN;
+ }
+
+ if (port == 0) {
+ port = LDNS_PORT;
+ }
+
+ /* First, get data from /etc/resolv.conf */
+ s = ldns_resolver_new_frm_file(&r1, NULL);
+ if (s != LDNS_STATUS_OK) {
+ return NULL;
+ }
+
+ r2 = ldns_resolver_new();
+ if (!r2) {
+ goto bad;
+ }
+ ldns_resolver_set_port(r2, port);
+
+ /* TSIG key data available? Copy into the resolver. */
+ if (tsig_cred) {
+ ldns_resolver_set_tsig_algorithm(r2, ldns_tsig_algorithm(tsig_cred));
+ ldns_resolver_set_tsig_keyname(r2, ldns_tsig_keyname(tsig_cred));
+ ldns_resolver_set_tsig_keydata(r2, ldns_tsig_keydata(tsig_cred));
+ }
+
+ /* Now get SOA zone, mname, NS, and construct r2. [RFC2136 4.3] */
+
+ /* Explicit 'zone' or no? */
+ if (zone) {
+ soa_zone = ldns_dname_new_frm_str(zone);
+ if (ldns_update_soa_mname(soa_zone, r1, class, &soa_mname)
+ != LDNS_STATUS_OK) {
+ goto bad;
+ }
+ } else {
+ if (ldns_update_soa_zone_mname(fqdn, r1, class, &soa_zone,
+ &soa_mname) != LDNS_STATUS_OK) {
+ goto bad;
+ }
+ }
+
+ /* Pass zone_rdf on upwards. */
+ *zone_rdf = ldns_rdf_clone(soa_zone);
+
+ /* NS */
+ query = ldns_pkt_query_new(soa_zone, LDNS_RR_TYPE_NS, class, LDNS_RD);
+ if (!query) {
+ goto bad;
+ }
+ soa_zone = NULL;
+
+ ldns_pkt_set_random_id(query);
+
+ if (ldns_resolver_send_pkt(&resp, r1, query) != LDNS_STATUS_OK) {
+ dprintf("%s", "NS query failed!\n");
+ goto bad;
+ }
+ ldns_pkt_free(query);
+ if (!resp) {
+ goto bad;
+ }
+ /* Match SOA MNAME to NS list, adding it first */
+ nslist = ldns_pkt_answer(resp);
+ for (i = 0; i < ldns_rr_list_rr_count(nslist); i++) {
+ ns_name = ldns_rr_rdf(ldns_rr_list_rr(nslist, i), 0);
+ if (!ns_name)
+ continue;
+ if (ldns_rdf_compare(soa_mname, ns_name) == 0) {
+ /* Match */
+ iplist = ldns_get_rr_list_addr_by_name(r1, ns_name, class, 0);
+ (void) ldns_resolver_push_nameserver_rr_list(r2, iplist);
+ ldns_rr_list_deep_free(iplist);
+ break;
+ }
+ }
+
+ /* Then all the other NSs. XXX Randomize? */
+ for (i = 0; i < ldns_rr_list_rr_count(nslist); i++) {
+ ns_name = ldns_rr_rdf(ldns_rr_list_rr(nslist, i), 0);
+ if (!ns_name)
+ continue;
+ if (ldns_rdf_compare(soa_mname, ns_name) != 0) {
+ /* No match, add it now. */
+ iplist = ldns_get_rr_list_addr_by_name(r1, ns_name, class, 0);
+ (void) ldns_resolver_push_nameserver_rr_list(r2, iplist);
+ ldns_rr_list_deep_free(iplist);
+ }
+ }
+
+ ldns_resolver_set_random(r2, false);
+ ldns_pkt_free(resp);
+ ldns_resolver_deep_free(r1);
+ if (soa_mname)
+ ldns_rdf_deep_free(soa_mname);
+ return r2;
+
+ bad:
+ if (r1)
+ ldns_resolver_deep_free(r1);
+ if (r2)
+ ldns_resolver_deep_free(r2);
+ if (query)
+ ldns_pkt_free(query);
+ if (resp)
+ ldns_pkt_free(resp);
+ if (soa_mname)
+ ldns_rdf_deep_free(soa_mname);
+ return NULL;
+}
+
+
+static ldns_status
+ldns_update_send_simple_addr(const char *fqdn, const char *zone,
+ const char *ipaddr, uint16_t p, uint32_t ttl, ldns_tsig_credentials *tsig_cred)
+{
+ ldns_resolver *res;
+ ldns_pkt *u_pkt = NULL, *r_pkt;
+ ldns_rr_list *up_rrlist;
+ ldns_rr *up_rr;
+ ldns_rdf *zone_rdf = NULL;
+ char *rrstr;
+ uint32_t rrstrlen, status = LDNS_STATUS_OK;
+
+ if (!fqdn || strlen(fqdn) == 0)
+ return LDNS_STATUS_ERR;
+
+ /* Create resolver */
+ res = ldns_update_resolver_new(fqdn, zone, 0, p, tsig_cred, &zone_rdf);
+ if (!res || !zone_rdf) {
+ goto cleanup;
+ }
+
+ /* Set up the update section. */
+ up_rrlist = ldns_rr_list_new();
+ if (!up_rrlist) {
+ goto cleanup;
+ }
+ /* Create input for ldns_rr_new_frm_str() */
+ if (ipaddr) {
+ /* We're adding A or AAAA */
+ rrstrlen = strlen(fqdn) + sizeof (" IN AAAA ") + strlen(ipaddr) + 1;
+ rrstr = (char *)malloc(rrstrlen);
+ if (!rrstr) {
+ ldns_rr_list_deep_free(up_rrlist);
+ goto cleanup;
+ }
+ snprintf(rrstr, rrstrlen, "%s IN %s %s", fqdn,
+ strchr(ipaddr, ':') ? "AAAA" : "A", ipaddr);
+
+ if (ldns_rr_new_frm_str(&up_rr, rrstr, ttl, NULL, NULL) !=
+ LDNS_STATUS_OK) {
+ ldns_rr_list_deep_free(up_rrlist);
+ free(rrstr);
+ goto cleanup;
+ }
+ free(rrstr);
+ ldns_rr_list_push_rr(up_rrlist, up_rr);
+ } else {
+ /* We're removing A and/or AAAA from 'fqdn'. [RFC2136 2.5.2] */
+ up_rr = ldns_rr_new();
+ ldns_rr_set_owner(up_rr, ldns_dname_new_frm_str(fqdn));
+ ldns_rr_set_ttl(up_rr, 0);
+ ldns_rr_set_class(up_rr, LDNS_RR_CLASS_ANY);
+
+ ldns_rr_set_type(up_rr, LDNS_RR_TYPE_A);
+ ldns_rr_list_push_rr(up_rrlist, ldns_rr_clone(up_rr));
+
+ ldns_rr_set_type(up_rr, LDNS_RR_TYPE_AAAA);
+ ldns_rr_list_push_rr(up_rrlist, up_rr);
+ }
+
+ /* Create update packet. */
+ u_pkt = ldns_update_pkt_new(zone_rdf, LDNS_RR_CLASS_IN, NULL, up_rrlist, NULL);
+ zone_rdf = NULL;
+ if (!u_pkt) {
+ ldns_rr_list_deep_free(up_rrlist);
+ goto cleanup;
+ }
+ ldns_pkt_set_random_id(u_pkt);
+
+ /* Add TSIG */
+ if (tsig_cred)
+ if (ldns_update_pkt_tsig_add(u_pkt, res) != LDNS_STATUS_OK) {
+ goto cleanup;
+ }
+
+ if (ldns_resolver_send_pkt(&r_pkt, res, u_pkt) != LDNS_STATUS_OK) {
+ goto cleanup;
+ }
+ ldns_pkt_free(u_pkt);
+ if (!r_pkt) {
+ goto cleanup;
+ }
+ if (ldns_pkt_get_rcode(r_pkt) != LDNS_RCODE_NOERROR) {
+ ldns_lookup_table *t = ldns_lookup_by_id(ldns_rcodes,
+ (int)ldns_pkt_get_rcode(r_pkt));
+ if (t) {
+ dprintf(";; UPDATE response was %s\n", t->name);
+ } else {
+ dprintf(";; UPDATE response was (%d)\n", ldns_pkt_get_rcode(r_pkt));
+ }
+ status = LDNS_STATUS_ERR;
+ }
+ ldns_pkt_free(r_pkt);
+ ldns_resolver_deep_free(res);
+ return status;
+
+ cleanup:
+ if (res)
+ ldns_resolver_deep_free(res);
+ if (u_pkt)
+ ldns_pkt_free(u_pkt);
+ if (zone_rdf)
+ ldns_rdf_deep_free(zone_rdf);
+ return LDNS_STATUS_ERR;
+}
+
+
+static void
+usage(FILE *fp, char *prog)
+{
+ fprintf(fp, "%s domain [zone] ip tsig_name tsig_alg tsig_hmac\n", prog);
+ fprintf(fp, " send a dynamic update packet to <ip>\n\n");
+ fprintf(fp, " Use 'none' instead of ip to remove any previous address\n");
+ fprintf(fp, " If 'zone' is not specified, try to figure it out from the zone's SOA\n");
+ fprintf(fp, " Example: %s my.example.org 1.2.3.4\n", prog);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ char *fqdn, *ipaddr, *zone, *prog;
+ ldns_status ret;
+ ldns_tsig_credentials tsig_cr, *tsig_cred;
+ int c = 2;
+ uint32_t defttl = 300;
+ uint32_t port = 53;
+
+ prog = strdup(argv[0]);
+
+ switch (argc) {
+ case 3:
+ case 4:
+ case 6:
+ case 7:
+ break;
+ default:
+ usage(stderr, prog);
+ exit(EXIT_FAILURE);
+ }
+
+ fqdn = argv[1];
+ c = 2;
+ if (argc == 4 || argc == 7) {
+ zone = argv[c++];
+ } else {
+ zone = NULL;
+ }
+
+ if (strcmp(argv[c], "none") == 0) {
+ ipaddr = NULL;
+ } else {
+ ipaddr = argv[c];
+ }
+ c++;
+ if (argc == 6 || argc == 7) {
+ tsig_cr.keyname = argv[c++];
+ if (strncasecmp(argv[c], "hmac-sha1", 9) == 0) {
+ tsig_cr.algorithm = (char*)"hmac-sha1.";
+ } else if (strncasecmp(argv[c], "hmac-md5", 8) == 0) {
+ tsig_cr.algorithm = (char*)"hmac-md5.sig-alg.reg.int.";
+ } else {
+ fprintf(stderr, "Unknown algorithm, try \"hmac-md5\" "
+ "or \"hmac-sha1\".\n");
+ exit(EXIT_FAILURE);
+ }
+ tsig_cr.keydata = argv[++c];
+ tsig_cred = &tsig_cr;
+ } else {
+ tsig_cred = NULL;
+ }
+
+ printf(";; trying UPDATE with FQDN \"%s\" and IP \"%s\"\n",
+ fqdn, ipaddr ? ipaddr : "<none>");
+ if (argc == 6 || argc == 7) {
+ printf(";; tsig: \"%s\" \"%s\" \"%s\"\n", tsig_cr.keyname,
+ tsig_cr.algorithm, tsig_cr.keydata);
+ }
+
+ ret = ldns_update_send_simple_addr(fqdn, zone, ipaddr, port, defttl, tsig_cred);
+ exit(ret);
+}