]> git.ipfire.org Git - thirdparty/ldns.git/commitdiff
Added ldns-notify. Capable of including the SOA serial in a NOTIFY.
authorWouter Wijngaards <wouter@NLnetLabs.nl>
Tue, 9 Jan 2007 12:37:33 +0000 (12:37 +0000)
committerWouter Wijngaards <wouter@NLnetLabs.nl>
Tue, 9 Jan 2007 12:37:33 +0000 (12:37 +0000)
Nice example, and useful to debug NSD.

examples/Makefile.in
examples/ldns-notify.c [new file with mode: 0644]

index 5903e041c01b53b017837da3e1e75de832d29ab1..8cfc780acd31a9d8ad4431f3c9ebea71a36d6512 100644 (file)
@@ -43,6 +43,7 @@ SOURCES       = ldns-read-zone.c \
                  ldns-resolver.c \
                  ldnsd.c \
                  ldns-keyfetcher.c \
+                 ldns-notify.c \
                  ldns-testns.c
 
 
diff --git a/examples/ldns-notify.c b/examples/ldns-notify.c
new file mode 100644 (file)
index 0000000..f159fcb
--- /dev/null
@@ -0,0 +1,303 @@
+/* 
+ * ldns-notify.c - ldns-notify(8)
+ * 
+ * Copyright (c) 2001-2005, NLnet Labs, All right reserved
+ *
+ * See LICENSE for the license
+ *
+ * send a notify packet to a server
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <netdb.h>
+#include <errno.h>
+
+/* ldns */
+#include "ldns/ldns.h"
+
+static int verbose = 1;
+
+static void
+usage(void)
+{
+       fprintf(stderr, "usage: ldns-notify [other options] -z zone <servers>\n");
+       fprintf(stderr, "Ldns notify utility\n\n");
+       fprintf(stderr, " Supported options:\n");
+       fprintf(stderr, "\t-z zone\t\tThe zone\n");
+       fprintf(stderr, "\t-s version\tSOA version number to include\n");
+       fprintf(stderr, "\t-y key:data\tTSIG sign the query\n");
+       fprintf(stderr, "\t-p port\t\tport to use to send to\n");
+       fprintf(stderr, "\t-v\t\tPrint version information\n");
+       fprintf(stderr, "\t-d\t\tPrint verbose debug information\n");
+       fprintf(stderr, "\t-h\t\tPrint this help information\n\n");
+       fprintf(stderr, "Report bugs to <ldns-team@nlnetlabs.nl>\n");
+       exit(1);
+}
+
+static void
+version(void)
+{
+        fprintf(stderr, "%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+        fprintf(stderr, "Written by NLnet Labs.\n\n");
+        fprintf(stderr,
+                "Copyright (C) 2001-2005 NLnet Labs.  This is free software.\n"
+                "There is NO warranty; not even for MERCHANTABILITY or FITNESS\n"
+                "FOR A PARTICULAR PURPOSE.\n");
+        exit(0);
+}
+
+static void
+notify_host(int s, struct addrinfo* res, uint8_t* wire, size_t wiresize,
+       const char* addrstr)
+{
+       int timeout_retry = 5; /* seconds */
+       int num_retry = 15; /* times to try */
+       fd_set rfds;
+       struct timeval tv;
+       int retval = 0;
+       ssize_t received = 0;
+       int got_ack = 0;
+       socklen_t addrlen = 0;
+       uint8_t replybuf[2048];
+       ldns_status status;
+       ldns_pkt* pkt = NULL;
+       
+       while(!got_ack) {
+               /* send it */
+               if(sendto(s, wire, wiresize, 0, res->ai_addr, res->ai_addrlen)
+                       == -1) {
+                       printf("warning: send to %s failed: %s\n",
+                               addrstr, strerror(errno));
+                       close(s);
+                       return;
+               }
+
+               /* wait for ACK packet */
+               FD_ZERO(&rfds);
+               FD_SET(s, &rfds);
+               tv.tv_sec = timeout_retry; /* seconds */
+               tv.tv_usec = 0; /* microseconds */
+               retval = select(s + 1, &rfds, NULL, NULL, &tv);
+               if (retval == -1) {
+                       printf("error waiting for reply from %s: %s\n",
+                               addrstr, strerror(errno));
+                       close(s);
+                       return;
+               }
+               if(retval == 0) {
+                       num_retry--;
+                       if(num_retry == 0) {
+                               printf("error: failed to send notify to %s.\n",
+                                       addrstr);
+                               exit(1);
+                       }
+                       printf("timeout (%d s) expired, retry notify to %s.\n",
+                               timeout_retry, addrstr);
+               }
+               if (retval == 1) {
+                       got_ack = 1;
+               }
+       }
+
+       /* got reply */
+       addrlen = res->ai_addrlen;
+       received = recvfrom(s, replybuf, sizeof(replybuf), 0,
+               res->ai_addr, &addrlen);
+       res->ai_addrlen = addrlen;
+
+       close(s);
+       if (received == -1) {
+               printf("recv %s failed: %s\n", addrstr, strerror(errno));
+               return;
+       }
+
+       /* check reply */
+       status = ldns_wire2pkt(&pkt, replybuf, (size_t)received);
+       if(status != LDNS_STATUS_OK) {
+               int i;
+               printf("Could not parse reply packet: %s\n",
+                       ldns_get_errorstr_by_id(status));
+               printf("hexdump of reply: ");
+               for(i=0; i<received; i++)
+                       printf("%02x", replybuf[i]);
+               printf("\n");
+               exit(1);
+       }
+
+       if(verbose) {
+               printf("# reply from %s:\n", addrstr);
+               ldns_pkt_print(stdout, pkt);
+       }
+       ldns_pkt_free(pkt);
+}
+
+int
+main(int argc, char **argv)
+{
+       int c;
+       int i;
+
+       /* LDNS types */
+       ldns_pkt *notify;
+       ldns_rr *question;
+       ldns_resolver *res;
+       ldns_rdf *ldns_zone_name = NULL;
+       ldns_status status;
+       const char *zone_name = NULL;
+       int include_soa = 0;
+       uint32_t soa_version = 0;
+       ldns_tsig_credentials tsig_cred = {0,0,0};
+       int do_hexdump = 1;
+       uint8_t *wire = NULL;
+       size_t wiresize = 0;
+       char *port = "53";
+
+       srandom(time(NULL) ^ getpid());
+       
+        while ((c = getopt(argc, argv, "vhdp:s:y:z:")) != -1) {
+                switch (c) {
+                case 'd':
+                       verbose = 1;
+                       break;
+                case 'p':
+                       port = optarg;
+                       break;
+                case 's':
+                       include_soa = 1;
+                       soa_version = (uint32_t)atoi(optarg);
+                       break;
+                case 'y':
+                       tsig_cred.algorithm = "hmac-md5.sig-alg.reg.int.";
+                       tsig_cred.keyname = optarg;
+                       tsig_cred.keydata = strchr(optarg, ':');
+                       *tsig_cred.keydata = '\0';
+                       tsig_cred.keydata++;
+                       printf("Sign with %s : %s\n", tsig_cred.keyname,
+                               tsig_cred.keydata);
+                       break;
+                case 'z':
+                       zone_name = optarg;
+                       ldns_zone_name = ldns_dname_new_frm_str(zone_name);
+                       if(!ldns_zone_name) {
+                               printf("cannot parse zone name: %s\n", 
+                                       zone_name);
+                               exit(1);
+                       }
+                        break;
+               case 'v':
+                       version();
+                case 'h':
+                case '?':
+                default:
+                        usage();
+                }
+        }
+        argc -= optind;
+        argv += optind;
+
+        if (argc == 0 || zone_name == NULL) {
+                usage();
+        }
+
+       notify = ldns_pkt_new();
+       question = ldns_rr_new();
+       res = ldns_resolver_new();
+
+       if (!notify || !question || !res) {
+               /* bail out */
+               printf("error: cannot create ldns types\n");
+               exit(1);
+       }
+
+       /* create the rr for inside the pkt */
+       ldns_rr_set_class(question, LDNS_RR_CLASS_IN);
+       ldns_rr_set_owner(question, ldns_zone_name);
+       ldns_rr_set_type(question, LDNS_RR_TYPE_SOA);
+       ldns_pkt_set_opcode(notify, LDNS_PACKET_NOTIFY);
+       ldns_pkt_push_rr(notify, LDNS_SECTION_QUESTION, question);
+       ldns_pkt_set_aa(notify, true);
+       ldns_pkt_set_id(notify, random()&0xffff);
+       if(include_soa) {
+               char buf[10240];
+               ldns_rr *soa_rr=NULL;
+               ldns_rdf *prev=NULL;
+               sprintf(buf, "%s 3600 IN SOA . . %u 0 0 0 0",
+                       zone_name, soa_version);
+               /*printf("Adding soa %s\n", buf);*/
+               status = ldns_rr_new_frm_str(&soa_rr, buf, 3600, NULL, &prev);
+               if(status != LDNS_STATUS_OK) {
+                       printf("Error adding SOA version: %s\n",
+                               ldns_get_errorstr_by_id(status));
+               }
+               ldns_pkt_push_rr(notify, LDNS_SECTION_ANSWER, soa_rr);
+       }
+
+       if(tsig_cred.keyname) {
+               status = ldns_pkt_tsig_sign(notify, tsig_cred.keyname,
+                       tsig_cred.keydata, 300, tsig_cred.algorithm,
+                       NULL);
+               if(status != LDNS_STATUS_OK) {
+                       printf("Error TSIG sign query: %s\n",
+                               ldns_get_errorstr_by_id(status));
+               }
+       }
+
+       if(verbose) {
+               printf("# Sending packet:\n");
+               ldns_pkt_print(stdout, notify);
+
+       }
+
+       status = ldns_pkt2wire(&wire, notify, &wiresize);
+       if(wiresize == 0) {
+               printf("Error converting notify packet to hex.\n");
+               exit(1);
+       }
+
+       if(do_hexdump && verbose) {
+               printf("Hexdump of notify packet:\n");
+               for(i=0; i<wiresize; i++)
+                       printf("%02x", wire[i]);
+               printf("\n");
+       }
+
+       for(i=0; i<argc; i++)
+       {
+               struct addrinfo hints, *res0, *res;
+               int error;
+               int default_family = AF_INET;
+
+               if(verbose)
+                       printf("# sending to %s\n", argv[i]);
+               memset(&hints, 0, sizeof(hints));
+               hints.ai_family = default_family;
+               hints.ai_socktype = SOCK_DGRAM;
+               hints.ai_protocol = IPPROTO_UDP;
+               error = getaddrinfo(argv[i], port, &hints, &res0);
+               if (error) {
+                       printf("skipping bad address: %s: %s\n", argv[i],
+                               gai_strerror(error));
+                       continue;
+               }
+               for (res = res0; res; res = res->ai_next) {
+                       int s = socket(res->ai_family, res->ai_socktype, 
+                               res->ai_protocol);
+                       if(s == -1)
+                               continue;
+                       /* send the notify */
+                       notify_host(s, res, wire, wiresize, argv[i]);
+               }
+               freeaddrinfo(res0);
+       }
+
+       ldns_pkt_free(notify);
+       free(wire);
+        return 0;
+}