notify.c revision 170222
1135446Strhodes/* 2170222Sdougb * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2003 Internet Software Consortium. 4135446Strhodes * 5135446Strhodes * Permission to use, copy, modify, and distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18170222Sdougb/* $Id: notify.c,v 1.30.18.3 2005/04/29 00:15:26 marka Exp $ */ 19135446Strhodes 20135446Strhodes#include <config.h> 21135446Strhodes 22135446Strhodes#include <isc/log.h> 23135446Strhodes#include <isc/print.h> 24135446Strhodes 25135446Strhodes#include <dns/message.h> 26135446Strhodes#include <dns/rdataset.h> 27135446Strhodes#include <dns/result.h> 28135446Strhodes#include <dns/view.h> 29135446Strhodes#include <dns/zone.h> 30135446Strhodes#include <dns/zt.h> 31135446Strhodes 32135446Strhodes#include <named/log.h> 33135446Strhodes#include <named/notify.h> 34135446Strhodes 35170222Sdougb/*! \file 36170222Sdougb * \brief 37170222Sdougb * This module implements notify as in RFC1996. 38135446Strhodes */ 39135446Strhodes 40135446Strhodesstatic void 41135446Strhodesnotify_log(ns_client_t *client, int level, const char *fmt, ...) { 42135446Strhodes va_list ap; 43135446Strhodes 44135446Strhodes va_start(ap, fmt); 45135446Strhodes ns_client_logv(client, DNS_LOGCATEGORY_NOTIFY, NS_LOGMODULE_NOTIFY, 46135446Strhodes level, fmt, ap); 47135446Strhodes va_end(ap); 48135446Strhodes} 49135446Strhodes 50135446Strhodesstatic void 51135446Strhodesrespond(ns_client_t *client, isc_result_t result) { 52135446Strhodes dns_rcode_t rcode; 53135446Strhodes dns_message_t *message; 54135446Strhodes isc_result_t msg_result; 55135446Strhodes 56135446Strhodes message = client->message; 57135446Strhodes rcode = dns_result_torcode(result); 58135446Strhodes 59135446Strhodes msg_result = dns_message_reply(message, ISC_TRUE); 60135446Strhodes if (msg_result != ISC_R_SUCCESS) 61135446Strhodes msg_result = dns_message_reply(message, ISC_FALSE); 62135446Strhodes if (msg_result != ISC_R_SUCCESS) { 63135446Strhodes ns_client_next(client, msg_result); 64135446Strhodes return; 65135446Strhodes } 66135446Strhodes message->rcode = rcode; 67135446Strhodes if (rcode == dns_rcode_noerror) 68135446Strhodes message->flags |= DNS_MESSAGEFLAG_AA; 69135446Strhodes else 70135446Strhodes message->flags &= ~DNS_MESSAGEFLAG_AA; 71135446Strhodes ns_client_send(client); 72135446Strhodes} 73135446Strhodes 74135446Strhodesvoid 75135446Strhodesns_notify_start(ns_client_t *client) { 76135446Strhodes dns_message_t *request = client->message; 77135446Strhodes isc_result_t result; 78135446Strhodes dns_name_t *zonename; 79135446Strhodes dns_rdataset_t *zone_rdataset; 80135446Strhodes dns_zone_t *zone = NULL; 81135446Strhodes char namebuf[DNS_NAME_FORMATSIZE]; 82135446Strhodes char tsigbuf[DNS_NAME_FORMATSIZE + sizeof(": TSIG ''")]; 83135446Strhodes dns_name_t *tsigname; 84135446Strhodes 85135446Strhodes /* 86135446Strhodes * Interpret the question section. 87135446Strhodes */ 88135446Strhodes result = dns_message_firstname(request, DNS_SECTION_QUESTION); 89135446Strhodes if (result != ISC_R_SUCCESS) { 90135446Strhodes notify_log(client, ISC_LOG_NOTICE, 91135446Strhodes "notify question section empty"); 92135446Strhodes goto formerr; 93135446Strhodes } 94135446Strhodes 95135446Strhodes /* 96135446Strhodes * The question section must contain exactly one question. 97135446Strhodes */ 98135446Strhodes zonename = NULL; 99135446Strhodes dns_message_currentname(request, DNS_SECTION_QUESTION, &zonename); 100135446Strhodes zone_rdataset = ISC_LIST_HEAD(zonename->list); 101135446Strhodes if (ISC_LIST_NEXT(zone_rdataset, link) != NULL) { 102135446Strhodes notify_log(client, ISC_LOG_NOTICE, 103135446Strhodes "notify question section contains multiple RRs"); 104135446Strhodes goto formerr; 105135446Strhodes } 106135446Strhodes 107135446Strhodes /* The zone section must have exactly one name. */ 108135446Strhodes result = dns_message_nextname(request, DNS_SECTION_ZONE); 109135446Strhodes if (result != ISC_R_NOMORE) { 110135446Strhodes notify_log(client, ISC_LOG_NOTICE, 111135446Strhodes "notify question section contains multiple RRs"); 112135446Strhodes goto formerr; 113135446Strhodes } 114135446Strhodes 115135446Strhodes /* The one rdataset must be an SOA. */ 116135446Strhodes if (zone_rdataset->type != dns_rdatatype_soa) { 117135446Strhodes notify_log(client, ISC_LOG_NOTICE, 118135446Strhodes "notify question section contains no SOA"); 119135446Strhodes goto formerr; 120135446Strhodes } 121135446Strhodes 122135446Strhodes tsigname = NULL; 123135446Strhodes if (dns_message_gettsig(request, &tsigname) != NULL) { 124135446Strhodes dns_name_format(tsigname, namebuf, sizeof(namebuf)); 125135446Strhodes snprintf(tsigbuf, sizeof(tsigbuf), ": TSIG '%s'", namebuf); 126135446Strhodes } else 127135446Strhodes tsigbuf[0] = '\0'; 128135446Strhodes dns_name_format(zonename, namebuf, sizeof(namebuf)); 129135446Strhodes result = dns_zt_find(client->view->zonetable, zonename, 0, NULL, 130135446Strhodes &zone); 131135446Strhodes if (result != ISC_R_SUCCESS) 132135446Strhodes goto notauth; 133135446Strhodes 134135446Strhodes switch (dns_zone_gettype(zone)) { 135135446Strhodes case dns_zone_master: 136135446Strhodes case dns_zone_slave: 137135446Strhodes case dns_zone_stub: /* Allow dialup passive to work. */ 138135446Strhodes notify_log(client, ISC_LOG_INFO, 139135446Strhodes "received notify for zone '%s'%s", namebuf, tsigbuf); 140135446Strhodes respond(client, dns_zone_notifyreceive(zone, 141135446Strhodes ns_client_getsockaddr(client), request)); 142135446Strhodes break; 143135446Strhodes default: 144135446Strhodes goto notauth; 145135446Strhodes } 146135446Strhodes dns_zone_detach(&zone); 147135446Strhodes return; 148135446Strhodes 149135446Strhodes notauth: 150135446Strhodes notify_log(client, ISC_LOG_NOTICE, 151135446Strhodes "received notify for zone '%s'%s: not authoritative", 152135446Strhodes namebuf, tsigbuf); 153135446Strhodes result = DNS_R_NOTAUTH; 154135446Strhodes goto failure; 155135446Strhodes 156135446Strhodes formerr: 157135446Strhodes result = DNS_R_FORMERR; 158135446Strhodes 159135446Strhodes failure: 160135446Strhodes if (zone != NULL) 161135446Strhodes dns_zone_detach(&zone); 162135446Strhodes respond(client, result); 163135446Strhodes} 164