summaryrefslogtreecommitdiff
path: root/examples/ldns-notify.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/ldns-notify.c')
-rw-r--r--examples/ldns-notify.c334
1 files changed, 334 insertions, 0 deletions
diff --git a/examples/ldns-notify.c b/examples/ldns-notify.c
new file mode 100644
index 000000000000..018a716faad4
--- /dev/null
+++ b/examples/ldns-notify.c
@@ -0,0 +1,334 @@
+/*
+ * ldns-notify.c - ldns-notify(8)
+ *
+ * Copyright (c) 2001-2008, NLnet Labs, All right reserved
+ *
+ * See LICENSE for the license
+ *
+ * send a notify packet to a server
+ */
+
+#include "config.h"
+
+/* ldns */
+#include <ldns/ldns.h>
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#include <errno.h>
+
+static int verbose = 1;
+static int max_num_retry = 15; /* times to try */
+
+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-r num\t\tmax number of retries (%d)\n",
+ max_num_retry);
+ 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-2008 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 = max_num_retry;
+#ifndef S_SPLINT_S
+ fd_set rfds;
+#endif
+ 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, (void*)wire, wiresize, 0,
+ res->ai_addr, res->ai_addrlen) == -1) {
+ printf("warning: send to %s failed: %s\n",
+ addrstr, strerror(errno));
+#ifndef USE_WINSOCK
+ close(s);
+#else
+ closesocket(s);
+#endif
+ return;
+ }
+
+ /* wait for ACK packet */
+#ifndef S_SPLINT_S
+ FD_ZERO(&rfds);
+ FD_SET(s, &rfds);
+ tv.tv_sec = timeout_retry; /* seconds */
+#endif
+ 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));
+#ifndef USE_WINSOCK
+ close(s);
+#else
+ closesocket(s);
+#endif
+ 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, (void*)replybuf, sizeof(replybuf), 0,
+ res->ai_addr, &addrlen);
+ res->ai_addrlen = addrlen;
+
+#ifndef USE_WINSOCK
+ close(s);
+#else
+ closesocket(s);
+#endif
+ 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) {
+ ssize_t i;
+ printf("Could not parse reply packet: %s\n",
+ ldns_get_errorstr_by_id(status));
+ if (verbose > 1) {
+ printf("hexdump of reply: ");
+ for(i=0; i<received; i++)
+ printf("%02x", (unsigned)replybuf[i]);
+ printf("\n");
+ }
+ exit(1);
+ }
+
+ if(verbose) {
+ ssize_t i;
+ printf("# reply from %s:\n", addrstr);
+ ldns_pkt_print(stdout, pkt);
+ if (verbose > 1) {
+ printf("hexdump of reply: ");
+ for(i=0; i<received; i++)
+ printf("%02x", (unsigned)replybuf[i]);
+ printf("\n");
+ }
+ }
+ 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;
+ const char *port = "53";
+
+ srandom(time(NULL) ^ getpid());
+
+ while ((c = getopt(argc, argv, "vhdp:r:s:y:z:")) != -1) {
+ switch (c) {
+ case 'd':
+ verbose++;
+ break;
+ case 'p':
+ port = optarg;
+ break;
+ case 'r':
+ max_num_retry = atoi(optarg);
+ break;
+ case 's':
+ include_soa = 1;
+ soa_version = (uint32_t)atoi(optarg);
+ break;
+ case 'y':
+ tsig_cred.algorithm = (char*)"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;
+ snprintf(buf, sizeof(buf), "%s 3600 IN SOA . . %u 0 0 0 0",
+ zone_name, (unsigned)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) {
+#ifdef HAVE_SSL
+ 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));
+ }
+#else
+ fprintf(stderr, "Warning: TSIG needs OpenSSL support, which has not been compiled in, TSIG skipped\n");
+#endif
+ }
+
+ 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 > 1) {
+ printf("Hexdump of notify packet:\n");
+ for(i=0; i<(int)wiresize; i++)
+ printf("%02x", (unsigned)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;
+}