summaryrefslogtreecommitdiffstats
path: root/usr.sbin/nsd/nsd-notify.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/nsd/nsd-notify.c')
-rw-r--r--usr.sbin/nsd/nsd-notify.c466
1 files changed, 0 insertions, 466 deletions
diff --git a/usr.sbin/nsd/nsd-notify.c b/usr.sbin/nsd/nsd-notify.c
deleted file mode 100644
index 91fd591340e..00000000000
--- a/usr.sbin/nsd/nsd-notify.c
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * nsd-notify.c -- sends notify(rfc1996) message to a list of servers
- *
- * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
- *
- * See LICENSE for the license.
- *
- */
-
-#include <config.h>
-
-#include <sys/types.h>
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <errno.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <tsig.h>
-#include <unistd.h>
-#include <netdb.h>
-
-#include "query.h"
-
-extern char *optarg;
-extern int optind;
-
-/*
- * Check if two getaddrinfo result lists have records with matching
- * ai_family fields.
- */
-int check_matching_address_family(struct addrinfo *a, struct addrinfo *b);
-
-/*
- * Returns the first record with ai_family == FAMILY, or NULL if no
- * such record is found.
- */
-struct addrinfo *find_by_address_family(struct addrinfo *addrs, int family);
-
-/*
- * Assigns pointers to hostname and port and wipes out the optional delimiter.
- */
-void get_hostname_port_frm_str(char* arg, const char** hostname,
- const char** port);
-
-/*
- * Log a warning message.
- */
-static void warning(const char *format, ...) ATTR_FORMAT(printf, 1, 2);
-static void
-warning(const char *format, ...)
-{
- va_list args;
- va_start(args, format);
- log_vmsg(LOG_WARNING, format, args);
- va_end(args);
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "usage: nsd-notify [-4] [-6] [-a src[@port] [-h] [-p \
-port] [-y key:secret[:algo]] -z zone servers\n\n");
- fprintf(stderr, "Send NOTIFY to secondary servers to force a zone \
-update.\n");
- fprintf(stderr, "Version %s. Report bugs to <%s>.\n\n",
- PACKAGE_VERSION, PACKAGE_BUGREPORT);
- fprintf(stderr, " -4 Send using IPv4.\n");
- fprintf(stderr, " -6 Send using IPv6.\n");
- fprintf(stderr, " -a src[@port] Local hostname/ip-address for "
- "the connection, including optional source port.\n");
- fprintf(stderr, " -h Print this help "
- "information.\n");
- fprintf(stderr, " -p port Port number of secondary "
- "server.\n");
- fprintf(stderr, " -y key:secret[:algo] TSIG keyname, base64 secret "
- "blob and HMAC algorithm.\n"
- " If algo is not provided, "
- "HMAC-MD5 is assumed.\n");
- fprintf(stderr, " -z zone Name of zone to be updated.\n");
- fprintf(stderr, " servers IP addresses of the secondary "
- "server(s).\n");
- exit(1);
-}
-
-/*
- * Send NOTIFY messages to the host, as in struct q,
- * waiting for ack packet (received in buffer answer).
- * Will retry transmission after a timeout.
- * addrstr is the string describing the address of the host.
- */
-static void
-notify_host(int udp_s, struct query* q, struct query *answer,
- struct addrinfo* res, const dname_type *zone, const char* addrstr)
-{
- int timeout_retry = 1; /* seconds */
- int num_retry = 6; /* times to try */
- fd_set rfds;
- struct timeval tv;
- int retval = 0;
- ssize_t received = 0;
- int got_ack = 0;
- socklen_t addrlen = 0;
-
- while(!got_ack) {
- /* WE ARE READY SEND IT OUT */
- if (sendto(udp_s,
- buffer_current(q->packet),
- buffer_remaining(q->packet), 0,
- res->ai_addr, res->ai_addrlen) == -1) {
- warning("send to %s failed: %s\n", addrstr,
- strerror(errno));
- close(udp_s);
- return;
- }
-
- /* wait for ACK packet */
- FD_ZERO(&rfds);
- FD_SET(udp_s, &rfds);
- tv.tv_sec = timeout_retry; /* seconds */
- tv.tv_usec = 0; /* microseconds */
- retval = select(udp_s + 1, &rfds, NULL, NULL, &tv);
- if (retval == -1) {
- warning("error waiting for reply from %s: %s\n",
- addrstr, strerror(errno));
- close(udp_s);
- return;
- }
- if (retval == 0) {
- num_retry--;
- if(num_retry == 0) {
- warning("error: failed to send notify to %s.\n",
- addrstr);
- exit(1);
- }
- warning("timeout (%d s) expired, retry notify to %s.\n",
- timeout_retry, addrstr);
- }
- if (retval == 1) {
- got_ack = 1;
- }
- /* Exponential backoff */
- timeout_retry *= 2;
- }
-
- /* receive reply */
- addrlen = res->ai_addrlen;
- received = recvfrom(udp_s, buffer_begin(answer->packet),
- buffer_remaining(answer->packet), 0,
- res->ai_addr, &addrlen);
- res->ai_addrlen = addrlen;
-
- if (received == -1) {
- warning("recv %s failed: %s\n", addrstr, strerror(errno));
- } else {
- /* check the answer */
- if ((ID(q->packet) == ID(answer->packet)) &&
- (OPCODE(answer->packet) == OPCODE_NOTIFY) &&
- AA(answer->packet) &&
- QR(answer->packet) && (RCODE(answer->packet) == RCODE_OK)) {
- /* no news is good news */
- /* info("reply from: %s, acknowledges notify.\n",
- addrstr); */
- } else {
- warning("bad reply from %s for zone %s, error response %s (%d).\n",
- addrstr, dname_to_string(zone, NULL), rcode2str(RCODE(answer->packet)),
- RCODE(answer->packet));
- }
- }
- close(udp_s);
-}
-
-static tsig_key_type*
-add_key(region_type* region, const char* opt, tsig_algorithm_type** algo)
-{
- /* parse -y key:secret_base64 format option */
- char* delim = strchr(opt, ':');
- char* delim2 = NULL;
- tsig_key_type *key = (tsig_key_type*)region_alloc(
- region, sizeof(tsig_key_type));
- size_t len;
- int sz;
-
- if (delim) {
- delim2 = strchr(delim+1, ':');
- }
-
- if(!key) {
- log_msg(LOG_ERR, "region_alloc failed (add_key)");
- return 0;
- }
-
- if(!delim) {
- log_msg(LOG_ERR, "bad key syntax %s", opt);
- return 0;
- }
- *delim = '\0';
- key->name = dname_parse(region, opt);
- if(!key->name) {
- log_msg(LOG_ERR, "bad key name %s", opt);
- return 0;
- }
- *delim = ':';
-
- if (!delim2)
- *algo = tsig_get_algorithm_by_name("hmac-md5");
- else {
- char* by_name = (char*) malloc(sizeof(char)*(5+strlen(delim2)));
- snprintf(by_name, 5+strlen(delim2), "%s", delim2+1);
- *algo = tsig_get_algorithm_by_name(by_name);
- free(by_name);
- *delim2 = '\0';
- }
-
- if (!(*algo)) {
- log_msg(LOG_ERR, "bad tsig algorithm %s", opt);
- return 0;
- }
-
- len = strlen(delim+1);
- key->data = region_alloc(region, len+1);
- if(!key->data) {
- log_msg(LOG_ERR, "region_alloc failed (add_key, key->data)");
- return 0;
- }
- sz= b64_pton(delim+1, (uint8_t*)key->data, len);
- if(sz == -1) {
- log_msg(LOG_ERR, "bad key syntax %s", opt);
- return 0;
- }
- key->size = sz;
- tsig_add_key(key);
- return key;
-}
-
-int
-main (int argc, char *argv[])
-{
- int c, udp_s;
- struct query q;
- struct query answer;
- const dname_type *zone = NULL;
- struct addrinfo hints, *res0, *res;
- int error;
- int default_family = DEFAULT_AI_FAMILY;
- const char *local_hostname = NULL;
- struct addrinfo *local_address, *local_addresses = NULL;
- const char *port = UDP_PORT;
- const char *local_port = NULL;
- region_type *region = region_create(xalloc, free);
- tsig_key_type *tsig_key = 0;
- tsig_record_type tsig;
- tsig_algorithm_type* algo = NULL;
-
- log_init("nsd-notify");
- if(!tsig_init(region)) {
- log_msg(LOG_ERR, "could not init tsig\n");
- exit(1);
- }
-
- srandom((unsigned long) getpid() * (unsigned long) time(NULL));
-
- /* Parse the command line... */
- while ((c = getopt(argc, argv, "46a:hp:y:z:")) != -1) {
- switch (c) {
- case '4':
- default_family = AF_INET;
- break;
- case '6':
-#ifdef INET6
- default_family = AF_INET6;
- break;
-#else /* !INET6 */
- log_msg(LOG_ERR, "IPv6 support not enabled\n");
- exit(1);
-#endif /* !INET6 */
- case 'a':
- get_hostname_port_frm_str((char *) optarg,
- &local_hostname, &local_port);
- break;
- case 'p':
- port = optarg;
- break;
- case 'y':
- if (!(tsig_key = add_key(region, optarg, &algo)))
- exit(1);
- break;
- case 'z':
- zone = dname_parse(region, optarg);
- if (!zone) {
- log_msg(LOG_ERR,
- "incorrect domain name '%s'",
- optarg);
- exit(1);
- }
- break;
- case 'h':
- default:
- usage();
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc == 0 || zone == NULL) {
- usage();
- }
-
- /* Initialize the query */
- memset(&q, 0, sizeof(struct query));
- q.addrlen = sizeof(q.addr);
- q.maxlen = 512;
- q.packet = buffer_create(region, QIOBUFSZ);
- memset(buffer_begin(q.packet), 0, buffer_remaining(q.packet));
-
- /* Set up the header */
- OPCODE_SET(q.packet, OPCODE_NOTIFY);
- ID_SET(q.packet, qid_generate());
- AA_SET(q.packet);
- QDCOUNT_SET(q.packet, 1);
- buffer_skip(q.packet, QHEADERSZ);
- buffer_write(q.packet, dname_name(zone), zone->name_size);
- buffer_write_u16(q.packet, TYPE_SOA);
- buffer_write_u16(q.packet, CLASS_IN);
- if(tsig_key) {
- assert(algo);
- tsig_create_record(&tsig, region);
- tsig_init_record(&tsig, algo, tsig_key);
- tsig_init_query(&tsig, ID(q.packet));
- tsig_prepare(&tsig);
- tsig_update(&tsig, q.packet, buffer_position(q.packet));
- tsig_sign(&tsig);
- tsig_append_rr(&tsig, q.packet);
- ARCOUNT_SET(q.packet, ARCOUNT(q.packet) + 1);
- }
- buffer_flip(q.packet);
-
- /* initialize buffer for ack */
- memset(&answer, 0, sizeof(struct query));
- answer.addrlen = sizeof(answer.addr);
- answer.maxlen = 512;
- answer.packet = buffer_create(region, QIOBUFSZ);
- memset(buffer_begin(answer.packet), 0, buffer_remaining(answer.packet));
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = default_family;
- hints.ai_socktype = SOCK_DGRAM;
- hints.ai_protocol = IPPROTO_UDP;
-
- if (local_hostname) {
- int rc = getaddrinfo(local_hostname, local_port,
- &hints, &local_addresses);
- if (rc) {
- warning("local hostname '%s' not found: %s",
- local_hostname, gai_strerror(rc));
- }
- }
-
- for (/*empty*/; *argv; argv++) {
- error = getaddrinfo(*argv, port, &hints, &res0);
- if (error) {
- warning("skipping bad address %s: %s\n", *argv,
- gai_strerror(error));
- continue;
- }
-
- if (local_addresses
- && !check_matching_address_family(res0, local_addresses))
- {
- warning("no local address family matches remote "
- "address family, skipping server '%s'",
- *argv);
- continue;
- }
-
- for (res = res0; res; res = res->ai_next) {
- if (res->ai_addrlen > (socklen_t)sizeof(q.addr)) {
- continue;
- }
-
- /*
- * If a local address is specified, use an
- * address with the same family as the remote
- * address.
- */
- local_address = find_by_address_family(local_addresses,
- res->ai_family);
- if (local_addresses && !local_address) {
- /* Continue with next remote address. */
- continue;
- }
-
- udp_s = socket(res->ai_family, res->ai_socktype,
- res->ai_protocol);
- if (udp_s == -1) {
- warning("cannot create socket: %s\n",
- strerror(errno));
- continue;
- }
-
- /* Bind socket to local address, if required. */
- if (local_address && bind(udp_s,
- local_address->ai_addr,
- local_address->ai_addrlen) < 0)
- {
- warning("cannot bind to %s: %s\n",
- local_hostname, strerror(errno));
- }
-
- memcpy(&q.addr, res->ai_addr, res->ai_addrlen);
- notify_host(udp_s, &q, &answer, res, zone, *argv);
- }
- freeaddrinfo(res0);
- }
- exit(0);
-}
-
-void
-get_hostname_port_frm_str(char* arg, const char** hostname,
- const char** port)
-{
- /* parse -a src[@port] option */
- char* delim = strchr(arg, '@');
-
- if (delim) {
- *delim = '\0';
- *port = delim+1;
- }
- *hostname = arg;
-}
-
-
-int
-check_matching_address_family(struct addrinfo *a0, struct addrinfo *b0)
-{
- struct addrinfo *a;
- struct addrinfo *b;
-
- for (a = a0; a; a = a->ai_next) {
- for (b = b0; b; b = b->ai_next) {
- if (a->ai_family == b->ai_family) {
- return 1;
- }
- }
- }
- return 0;
-}
-
-struct addrinfo *
-find_by_address_family(struct addrinfo *addrs, int family)
-{
- for (; addrs; addrs = addrs->ai_next) {
- if (addrs->ai_family == family) {
- return addrs;
- }
- }
- return NULL;
-}
-