1*00b67f09SDavid van Moolenbroek /* $NetBSD: notify.c,v 1.4 2014/12/10 04:37:51 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek * Copyright (C) 1999-2003 Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek *
7*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek *
11*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek */
19*00b67f09SDavid van Moolenbroek
20*00b67f09SDavid van Moolenbroek /* Id: notify.c,v 1.37 2007/06/19 23:46:59 tbox Exp */
21*00b67f09SDavid van Moolenbroek
22*00b67f09SDavid van Moolenbroek #include <config.h>
23*00b67f09SDavid van Moolenbroek
24*00b67f09SDavid van Moolenbroek #include <isc/log.h>
25*00b67f09SDavid van Moolenbroek #include <isc/print.h>
26*00b67f09SDavid van Moolenbroek
27*00b67f09SDavid van Moolenbroek #include <dns/message.h>
28*00b67f09SDavid van Moolenbroek #include <dns/rdataset.h>
29*00b67f09SDavid van Moolenbroek #include <dns/result.h>
30*00b67f09SDavid van Moolenbroek #include <dns/tsig.h>
31*00b67f09SDavid van Moolenbroek #include <dns/view.h>
32*00b67f09SDavid van Moolenbroek #include <dns/zone.h>
33*00b67f09SDavid van Moolenbroek #include <dns/zt.h>
34*00b67f09SDavid van Moolenbroek
35*00b67f09SDavid van Moolenbroek #include <named/log.h>
36*00b67f09SDavid van Moolenbroek #include <named/notify.h>
37*00b67f09SDavid van Moolenbroek
38*00b67f09SDavid van Moolenbroek /*! \file
39*00b67f09SDavid van Moolenbroek * \brief
40*00b67f09SDavid van Moolenbroek * This module implements notify as in RFC1996.
41*00b67f09SDavid van Moolenbroek */
42*00b67f09SDavid van Moolenbroek
43*00b67f09SDavid van Moolenbroek static void
notify_log(ns_client_t * client,int level,const char * fmt,...)44*00b67f09SDavid van Moolenbroek notify_log(ns_client_t *client, int level, const char *fmt, ...) {
45*00b67f09SDavid van Moolenbroek va_list ap;
46*00b67f09SDavid van Moolenbroek
47*00b67f09SDavid van Moolenbroek va_start(ap, fmt);
48*00b67f09SDavid van Moolenbroek ns_client_logv(client, DNS_LOGCATEGORY_NOTIFY, NS_LOGMODULE_NOTIFY,
49*00b67f09SDavid van Moolenbroek level, fmt, ap);
50*00b67f09SDavid van Moolenbroek va_end(ap);
51*00b67f09SDavid van Moolenbroek }
52*00b67f09SDavid van Moolenbroek
53*00b67f09SDavid van Moolenbroek static void
respond(ns_client_t * client,isc_result_t result)54*00b67f09SDavid van Moolenbroek respond(ns_client_t *client, isc_result_t result) {
55*00b67f09SDavid van Moolenbroek dns_rcode_t rcode;
56*00b67f09SDavid van Moolenbroek dns_message_t *message;
57*00b67f09SDavid van Moolenbroek isc_result_t msg_result;
58*00b67f09SDavid van Moolenbroek
59*00b67f09SDavid van Moolenbroek message = client->message;
60*00b67f09SDavid van Moolenbroek rcode = dns_result_torcode(result);
61*00b67f09SDavid van Moolenbroek
62*00b67f09SDavid van Moolenbroek msg_result = dns_message_reply(message, ISC_TRUE);
63*00b67f09SDavid van Moolenbroek if (msg_result != ISC_R_SUCCESS)
64*00b67f09SDavid van Moolenbroek msg_result = dns_message_reply(message, ISC_FALSE);
65*00b67f09SDavid van Moolenbroek if (msg_result != ISC_R_SUCCESS) {
66*00b67f09SDavid van Moolenbroek ns_client_next(client, msg_result);
67*00b67f09SDavid van Moolenbroek return;
68*00b67f09SDavid van Moolenbroek }
69*00b67f09SDavid van Moolenbroek message->rcode = rcode;
70*00b67f09SDavid van Moolenbroek if (rcode == dns_rcode_noerror)
71*00b67f09SDavid van Moolenbroek message->flags |= DNS_MESSAGEFLAG_AA;
72*00b67f09SDavid van Moolenbroek else
73*00b67f09SDavid van Moolenbroek message->flags &= ~DNS_MESSAGEFLAG_AA;
74*00b67f09SDavid van Moolenbroek ns_client_send(client);
75*00b67f09SDavid van Moolenbroek }
76*00b67f09SDavid van Moolenbroek
77*00b67f09SDavid van Moolenbroek void
ns_notify_start(ns_client_t * client)78*00b67f09SDavid van Moolenbroek ns_notify_start(ns_client_t *client) {
79*00b67f09SDavid van Moolenbroek dns_message_t *request = client->message;
80*00b67f09SDavid van Moolenbroek isc_result_t result;
81*00b67f09SDavid van Moolenbroek dns_name_t *zonename;
82*00b67f09SDavid van Moolenbroek dns_rdataset_t *zone_rdataset;
83*00b67f09SDavid van Moolenbroek dns_zone_t *zone = NULL;
84*00b67f09SDavid van Moolenbroek char namebuf[DNS_NAME_FORMATSIZE];
85*00b67f09SDavid van Moolenbroek char tsigbuf[DNS_NAME_FORMATSIZE + sizeof(": TSIG ''")];
86*00b67f09SDavid van Moolenbroek dns_tsigkey_t *tsigkey;
87*00b67f09SDavid van Moolenbroek
88*00b67f09SDavid van Moolenbroek /*
89*00b67f09SDavid van Moolenbroek * Interpret the question section.
90*00b67f09SDavid van Moolenbroek */
91*00b67f09SDavid van Moolenbroek result = dns_message_firstname(request, DNS_SECTION_QUESTION);
92*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
93*00b67f09SDavid van Moolenbroek notify_log(client, ISC_LOG_NOTICE,
94*00b67f09SDavid van Moolenbroek "notify question section empty");
95*00b67f09SDavid van Moolenbroek goto formerr;
96*00b67f09SDavid van Moolenbroek }
97*00b67f09SDavid van Moolenbroek
98*00b67f09SDavid van Moolenbroek /*
99*00b67f09SDavid van Moolenbroek * The question section must contain exactly one question.
100*00b67f09SDavid van Moolenbroek */
101*00b67f09SDavid van Moolenbroek zonename = NULL;
102*00b67f09SDavid van Moolenbroek dns_message_currentname(request, DNS_SECTION_QUESTION, &zonename);
103*00b67f09SDavid van Moolenbroek zone_rdataset = ISC_LIST_HEAD(zonename->list);
104*00b67f09SDavid van Moolenbroek if (ISC_LIST_NEXT(zone_rdataset, link) != NULL) {
105*00b67f09SDavid van Moolenbroek notify_log(client, ISC_LOG_NOTICE,
106*00b67f09SDavid van Moolenbroek "notify question section contains multiple RRs");
107*00b67f09SDavid van Moolenbroek goto formerr;
108*00b67f09SDavid van Moolenbroek }
109*00b67f09SDavid van Moolenbroek
110*00b67f09SDavid van Moolenbroek /* The zone section must have exactly one name. */
111*00b67f09SDavid van Moolenbroek result = dns_message_nextname(request, DNS_SECTION_ZONE);
112*00b67f09SDavid van Moolenbroek if (result != ISC_R_NOMORE) {
113*00b67f09SDavid van Moolenbroek notify_log(client, ISC_LOG_NOTICE,
114*00b67f09SDavid van Moolenbroek "notify question section contains multiple RRs");
115*00b67f09SDavid van Moolenbroek goto formerr;
116*00b67f09SDavid van Moolenbroek }
117*00b67f09SDavid van Moolenbroek
118*00b67f09SDavid van Moolenbroek /* The one rdataset must be an SOA. */
119*00b67f09SDavid van Moolenbroek if (zone_rdataset->type != dns_rdatatype_soa) {
120*00b67f09SDavid van Moolenbroek notify_log(client, ISC_LOG_NOTICE,
121*00b67f09SDavid van Moolenbroek "notify question section contains no SOA");
122*00b67f09SDavid van Moolenbroek goto formerr;
123*00b67f09SDavid van Moolenbroek }
124*00b67f09SDavid van Moolenbroek
125*00b67f09SDavid van Moolenbroek tsigkey = dns_message_gettsigkey(request);
126*00b67f09SDavid van Moolenbroek if (tsigkey != NULL) {
127*00b67f09SDavid van Moolenbroek dns_name_format(&tsigkey->name, namebuf, sizeof(namebuf));
128*00b67f09SDavid van Moolenbroek
129*00b67f09SDavid van Moolenbroek if (tsigkey->generated) {
130*00b67f09SDavid van Moolenbroek char cnamebuf[DNS_NAME_FORMATSIZE];
131*00b67f09SDavid van Moolenbroek dns_name_format(tsigkey->creator, cnamebuf,
132*00b67f09SDavid van Moolenbroek sizeof(cnamebuf));
133*00b67f09SDavid van Moolenbroek snprintf(tsigbuf, sizeof(tsigbuf), ": TSIG '%s' (%s)",
134*00b67f09SDavid van Moolenbroek namebuf, cnamebuf);
135*00b67f09SDavid van Moolenbroek } else {
136*00b67f09SDavid van Moolenbroek snprintf(tsigbuf, sizeof(tsigbuf), ": TSIG '%s'",
137*00b67f09SDavid van Moolenbroek namebuf);
138*00b67f09SDavid van Moolenbroek }
139*00b67f09SDavid van Moolenbroek } else
140*00b67f09SDavid van Moolenbroek tsigbuf[0] = '\0';
141*00b67f09SDavid van Moolenbroek dns_name_format(zonename, namebuf, sizeof(namebuf));
142*00b67f09SDavid van Moolenbroek result = dns_zt_find(client->view->zonetable, zonename, 0, NULL,
143*00b67f09SDavid van Moolenbroek &zone);
144*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
145*00b67f09SDavid van Moolenbroek goto notauth;
146*00b67f09SDavid van Moolenbroek
147*00b67f09SDavid van Moolenbroek switch (dns_zone_gettype(zone)) {
148*00b67f09SDavid van Moolenbroek case dns_zone_master:
149*00b67f09SDavid van Moolenbroek case dns_zone_slave:
150*00b67f09SDavid van Moolenbroek case dns_zone_stub: /* Allow dialup passive to work. */
151*00b67f09SDavid van Moolenbroek notify_log(client, ISC_LOG_INFO,
152*00b67f09SDavid van Moolenbroek "received notify for zone '%s'%s", namebuf, tsigbuf);
153*00b67f09SDavid van Moolenbroek respond(client, dns_zone_notifyreceive(zone,
154*00b67f09SDavid van Moolenbroek ns_client_getsockaddr(client), request));
155*00b67f09SDavid van Moolenbroek break;
156*00b67f09SDavid van Moolenbroek default:
157*00b67f09SDavid van Moolenbroek goto notauth;
158*00b67f09SDavid van Moolenbroek }
159*00b67f09SDavid van Moolenbroek dns_zone_detach(&zone);
160*00b67f09SDavid van Moolenbroek return;
161*00b67f09SDavid van Moolenbroek
162*00b67f09SDavid van Moolenbroek notauth:
163*00b67f09SDavid van Moolenbroek notify_log(client, ISC_LOG_NOTICE,
164*00b67f09SDavid van Moolenbroek "received notify for zone '%s'%s: not authoritative",
165*00b67f09SDavid van Moolenbroek namebuf, tsigbuf);
166*00b67f09SDavid van Moolenbroek result = DNS_R_NOTAUTH;
167*00b67f09SDavid van Moolenbroek goto failure;
168*00b67f09SDavid van Moolenbroek
169*00b67f09SDavid van Moolenbroek formerr:
170*00b67f09SDavid van Moolenbroek result = DNS_R_FORMERR;
171*00b67f09SDavid van Moolenbroek
172*00b67f09SDavid van Moolenbroek failure:
173*00b67f09SDavid van Moolenbroek if (zone != NULL)
174*00b67f09SDavid van Moolenbroek dns_zone_detach(&zone);
175*00b67f09SDavid van Moolenbroek respond(client, result);
176*00b67f09SDavid van Moolenbroek }
177