notify.c 4.68 KB
Newer Older
Mark Andrews's avatar
Mark Andrews committed
1
/*
Mark Andrews's avatar
Mark Andrews committed
2
 * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 1999-2003  Internet Software Consortium.
4
 *
Mark Andrews's avatar
Mark Andrews committed
5 6 7
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
8
 *
Mark Andrews's avatar
Mark Andrews committed
9 10 11 12 13 14 15
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
Mark Andrews's avatar
Mark Andrews committed
16 17
 */

18
/* $Id: notify.c,v 1.34 2006/12/04 01:52:45 marka Exp $ */
David Lawrence's avatar
David Lawrence committed
19

Mark Andrews's avatar
Mark Andrews committed
20 21
#include <config.h>

Brian Wellington's avatar
Brian Wellington committed
22
#include <isc/log.h>
23
#include <isc/print.h>
Brian Wellington's avatar
Brian Wellington committed
24

Mark Andrews's avatar
Mark Andrews committed
25 26 27
#include <dns/message.h>
#include <dns/rdataset.h>
#include <dns/result.h>
28
#include <dns/tsig.h>
Mark Andrews's avatar
Mark Andrews committed
29 30 31 32 33 34 35
#include <dns/view.h>
#include <dns/zone.h>
#include <dns/zt.h>

#include <named/log.h>
#include <named/notify.h>

36 37 38
/*! \file
 * \brief
 * This module implements notify as in RFC1996.
Mark Andrews's avatar
Mark Andrews committed
39
 */
40

Brian Wellington's avatar
Brian Wellington committed
41
static void
42
notify_log(ns_client_t *client, int level, const char *fmt, ...) {
Brian Wellington's avatar
Brian Wellington committed
43
	va_list ap;
Mark Andrews's avatar
Mark Andrews committed
44

Brian Wellington's avatar
Brian Wellington committed
45
	va_start(ap, fmt);
46
	ns_client_logv(client, DNS_LOGCATEGORY_NOTIFY, NS_LOGMODULE_NOTIFY,
Brian Wellington's avatar
Brian Wellington committed
47 48 49
		       level, fmt, ap);
	va_end(ap);
}
Mark Andrews's avatar
Mark Andrews committed
50 51

static void
52
respond(ns_client_t *client, isc_result_t result) {
Mark Andrews's avatar
Mark Andrews committed
53
	dns_rcode_t rcode;
Brian Wellington's avatar
Brian Wellington committed
54 55
	dns_message_t *message;
	isc_result_t msg_result;
Mark Andrews's avatar
Mark Andrews committed
56 57

	message = client->message;
58
	rcode = dns_result_torcode(result);
Mark Andrews's avatar
Mark Andrews committed
59 60 61 62 63 64 65 66 67

	msg_result = dns_message_reply(message, ISC_TRUE);
	if (msg_result != ISC_R_SUCCESS)
		msg_result = dns_message_reply(message, ISC_FALSE);
	if (msg_result != ISC_R_SUCCESS) {
		ns_client_next(client, msg_result);
		return;
	}
	message->rcode = rcode;
Mark Andrews's avatar
Mark Andrews committed
68 69 70 71
	if (rcode == dns_rcode_noerror)
		message->flags |= DNS_MESSAGEFLAG_AA;
	else
		message->flags &= ~DNS_MESSAGEFLAG_AA;
Mark Andrews's avatar
Mark Andrews committed
72
	ns_client_send(client);
Mark Andrews's avatar
Mark Andrews committed
73 74 75
}

void
76
ns_notify_start(ns_client_t *client) {
Mark Andrews's avatar
Mark Andrews committed
77
	dns_message_t *request = client->message;
78
	isc_result_t result;
Mark Andrews's avatar
Mark Andrews committed
79 80 81
	dns_name_t *zonename;
	dns_rdataset_t *zone_rdataset;
	dns_zone_t *zone = NULL;
82 83
	char namebuf[DNS_NAME_FORMATSIZE];
	char tsigbuf[DNS_NAME_FORMATSIZE + sizeof(": TSIG ''")];
84
	dns_tsigkey_t *tsigkey;
85

Mark Andrews's avatar
Mark Andrews committed
86 87 88 89
	/*
	 * Interpret the question section.
	 */
	result = dns_message_firstname(request, DNS_SECTION_QUESTION);
Brian Wellington's avatar
Brian Wellington committed
90
	if (result != ISC_R_SUCCESS) {
91 92 93
		notify_log(client, ISC_LOG_NOTICE,
			   "notify question section empty");
		goto formerr;
Brian Wellington's avatar
Brian Wellington committed
94
	}
Mark Andrews's avatar
Mark Andrews committed
95 96 97 98 99 100 101

	/*
	 * The question section must contain exactly one question.
	 */
	zonename = NULL;
	dns_message_currentname(request, DNS_SECTION_QUESTION, &zonename);
	zone_rdataset = ISC_LIST_HEAD(zonename->list);
Brian Wellington's avatar
Brian Wellington committed
102
	if (ISC_LIST_NEXT(zone_rdataset, link) != NULL) {
103
		notify_log(client, ISC_LOG_NOTICE,
Brian Wellington's avatar
Brian Wellington committed
104
			   "notify question section contains multiple RRs");
105
		goto formerr;
Brian Wellington's avatar
Brian Wellington committed
106
	}
Mark Andrews's avatar
Mark Andrews committed
107 108 109

	/* The zone section must have exactly one name. */
	result = dns_message_nextname(request, DNS_SECTION_ZONE);
Brian Wellington's avatar
Brian Wellington committed
110
	if (result != ISC_R_NOMORE) {
111
		notify_log(client, ISC_LOG_NOTICE,
Brian Wellington's avatar
Brian Wellington committed
112
			   "notify question section contains multiple RRs");
113
		goto formerr;
Brian Wellington's avatar
Brian Wellington committed
114 115 116 117
	}

	/* The one rdataset must be an SOA. */
	if (zone_rdataset->type != dns_rdatatype_soa) {
118
		notify_log(client, ISC_LOG_NOTICE,
Brian Wellington's avatar
Brian Wellington committed
119
			   "notify question section contains no SOA");
120
		goto formerr;
Brian Wellington's avatar
Brian Wellington committed
121
	}
Mark Andrews's avatar
Mark Andrews committed
122

123 124 125 126 127 128 129 130 131 132 133 134 135 136
	tsigkey = dns_message_gettsigkey(request);
	if (tsigkey != NULL) {
		dns_name_format(&tsigkey->name, namebuf, sizeof(namebuf));

		if (tsigkey->generated) {
			char cnamebuf[DNS_NAME_FORMATSIZE];
			dns_name_format(tsigkey->creator, cnamebuf,
					sizeof(cnamebuf));
			snprintf(tsigbuf, sizeof(tsigbuf), ": TSIG '%s' (%s)",
				 namebuf, cnamebuf);
		} else {
			snprintf(tsigbuf, sizeof(tsigbuf), ": TSIG '%s'",
				 namebuf);
		}
137 138 139
	} else
		tsigbuf[0] = '\0';
	dns_name_format(zonename, namebuf, sizeof(namebuf));
Bob Halley's avatar
Bob Halley committed
140 141
	result = dns_zt_find(client->view->zonetable, zonename, 0, NULL,
			     &zone);
142 143
	if (result != ISC_R_SUCCESS)
		goto notauth;
Mark Andrews's avatar
Mark Andrews committed
144

Andreas Gustafsson's avatar
spacing  
Andreas Gustafsson committed
145
	switch (dns_zone_gettype(zone)) {
Mark Andrews's avatar
Mark Andrews committed
146 147
	case dns_zone_master:
	case dns_zone_slave:
148
	case dns_zone_stub:	/* Allow dialup passive to work. */
Mark Andrews's avatar
Mark Andrews committed
149
		notify_log(client, ISC_LOG_INFO,
150
			   "received notify for zone '%s'%s", namebuf, tsigbuf);
Mark Andrews's avatar
Mark Andrews committed
151 152
		respond(client, dns_zone_notifyreceive(zone,
			ns_client_getsockaddr(client), request));
Mark Andrews's avatar
Mark Andrews committed
153
		break;
Mark Andrews's avatar
Mark Andrews committed
154
	default:
155
		goto notauth;
Mark Andrews's avatar
Mark Andrews committed
156
	}
157
	dns_zone_detach(&zone);
Mark Andrews's avatar
Mark Andrews committed
158
	return;
159

160 161 162 163 164 165 166 167 168 169
 notauth:
	notify_log(client, ISC_LOG_NOTICE,
		   "received notify for zone '%s'%s: not authoritative",
		   namebuf, tsigbuf);
	result = DNS_R_NOTAUTH;
	goto failure;

 formerr:
	result = DNS_R_FORMERR;

Mark Andrews's avatar
Mark Andrews committed
170
 failure:
171 172
	if (zone != NULL)
		dns_zone_detach(&zone);
Mark Andrews's avatar
Mark Andrews committed
173 174
	respond(client, result);
}