notify.c revision 135446
1135446Strhodes/* 2135446Strhodes * Copyright (C) 2004 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 18135446Strhodes/* $Id: notify.c,v 1.24.2.2.2.7 2004/08/28 06:25:30 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 35135446Strhodes/* 36135446Strhodes * This module implements notify as in RFC 1996. 37135446Strhodes */ 38135446Strhodes 39135446Strhodesstatic void 40135446Strhodesnotify_log(ns_client_t *client, int level, const char *fmt, ...) { 41135446Strhodes va_list ap; 42135446Strhodes 43135446Strhodes va_start(ap, fmt); 44135446Strhodes ns_client_logv(client, DNS_LOGCATEGORY_NOTIFY, NS_LOGMODULE_NOTIFY, 45135446Strhodes level, fmt, ap); 46135446Strhodes va_end(ap); 47135446Strhodes} 48135446Strhodes 49135446Strhodesstatic void 50135446Strhodesrespond(ns_client_t *client, isc_result_t result) { 51135446Strhodes dns_rcode_t rcode; 52135446Strhodes dns_message_t *message; 53135446Strhodes isc_result_t msg_result; 54135446Strhodes 55135446Strhodes message = client->message; 56135446Strhodes rcode = dns_result_torcode(result); 57135446Strhodes 58135446Strhodes msg_result = dns_message_reply(message, ISC_TRUE); 59135446Strhodes if (msg_result != ISC_R_SUCCESS) 60135446Strhodes msg_result = dns_message_reply(message, ISC_FALSE); 61135446Strhodes if (msg_result != ISC_R_SUCCESS) { 62135446Strhodes ns_client_next(client, msg_result); 63135446Strhodes return; 64135446Strhodes } 65135446Strhodes message->rcode = rcode; 66135446Strhodes if (rcode == dns_rcode_noerror) 67135446Strhodes message->flags |= DNS_MESSAGEFLAG_AA; 68135446Strhodes else 69135446Strhodes message->flags &= ~DNS_MESSAGEFLAG_AA; 70135446Strhodes ns_client_send(client); 71135446Strhodes} 72135446Strhodes 73135446Strhodesvoid 74135446Strhodesns_notify_start(ns_client_t *client) { 75135446Strhodes dns_message_t *request = client->message; 76135446Strhodes isc_result_t result; 77135446Strhodes dns_name_t *zonename; 78135446Strhodes dns_rdataset_t *zone_rdataset; 79135446Strhodes dns_zone_t *zone = NULL; 80135446Strhodes char namebuf[DNS_NAME_FORMATSIZE]; 81135446Strhodes char tsigbuf[DNS_NAME_FORMATSIZE + sizeof(": TSIG ''")]; 82135446Strhodes dns_name_t *tsigname; 83135446Strhodes 84135446Strhodes /* 85135446Strhodes * Interpret the question section. 86135446Strhodes */ 87135446Strhodes result = dns_message_firstname(request, DNS_SECTION_QUESTION); 88135446Strhodes if (result != ISC_R_SUCCESS) { 89135446Strhodes notify_log(client, ISC_LOG_NOTICE, 90135446Strhodes "notify question section empty"); 91135446Strhodes goto formerr; 92135446Strhodes } 93135446Strhodes 94135446Strhodes /* 95135446Strhodes * The question section must contain exactly one question. 96135446Strhodes */ 97135446Strhodes zonename = NULL; 98135446Strhodes dns_message_currentname(request, DNS_SECTION_QUESTION, &zonename); 99135446Strhodes zone_rdataset = ISC_LIST_HEAD(zonename->list); 100135446Strhodes if (ISC_LIST_NEXT(zone_rdataset, link) != NULL) { 101135446Strhodes notify_log(client, ISC_LOG_NOTICE, 102135446Strhodes "notify question section contains multiple RRs"); 103135446Strhodes goto formerr; 104135446Strhodes } 105135446Strhodes 106135446Strhodes /* The zone section must have exactly one name. */ 107135446Strhodes result = dns_message_nextname(request, DNS_SECTION_ZONE); 108135446Strhodes if (result != ISC_R_NOMORE) { 109135446Strhodes notify_log(client, ISC_LOG_NOTICE, 110135446Strhodes "notify question section contains multiple RRs"); 111135446Strhodes goto formerr; 112135446Strhodes } 113135446Strhodes 114135446Strhodes /* The one rdataset must be an SOA. */ 115135446Strhodes if (zone_rdataset->type != dns_rdatatype_soa) { 116135446Strhodes notify_log(client, ISC_LOG_NOTICE, 117135446Strhodes "notify question section contains no SOA"); 118135446Strhodes goto formerr; 119135446Strhodes } 120135446Strhodes 121135446Strhodes tsigname = NULL; 122135446Strhodes if (dns_message_gettsig(request, &tsigname) != NULL) { 123135446Strhodes dns_name_format(tsigname, namebuf, sizeof(namebuf)); 124135446Strhodes snprintf(tsigbuf, sizeof(tsigbuf), ": TSIG '%s'", namebuf); 125135446Strhodes } else 126135446Strhodes tsigbuf[0] = '\0'; 127135446Strhodes dns_name_format(zonename, namebuf, sizeof(namebuf)); 128135446Strhodes result = dns_zt_find(client->view->zonetable, zonename, 0, NULL, 129135446Strhodes &zone); 130135446Strhodes if (result != ISC_R_SUCCESS) 131135446Strhodes goto notauth; 132135446Strhodes 133135446Strhodes switch (dns_zone_gettype(zone)) { 134135446Strhodes case dns_zone_master: 135135446Strhodes case dns_zone_slave: 136135446Strhodes case dns_zone_stub: /* Allow dialup passive to work. */ 137135446Strhodes notify_log(client, ISC_LOG_INFO, 138135446Strhodes "received notify for zone '%s'%s", namebuf, tsigbuf); 139135446Strhodes respond(client, dns_zone_notifyreceive(zone, 140135446Strhodes ns_client_getsockaddr(client), request)); 141135446Strhodes break; 142135446Strhodes default: 143135446Strhodes goto notauth; 144135446Strhodes } 145135446Strhodes dns_zone_detach(&zone); 146135446Strhodes return; 147135446Strhodes 148135446Strhodes notauth: 149135446Strhodes notify_log(client, ISC_LOG_NOTICE, 150135446Strhodes "received notify for zone '%s'%s: not authoritative", 151135446Strhodes namebuf, tsigbuf); 152135446Strhodes result = DNS_R_NOTAUTH; 153135446Strhodes goto failure; 154135446Strhodes 155135446Strhodes formerr: 156135446Strhodes result = DNS_R_FORMERR; 157135446Strhodes 158135446Strhodes failure: 159135446Strhodes if (zone != NULL) 160135446Strhodes dns_zone_detach(&zone); 161135446Strhodes respond(client, result); 162135446Strhodes} 163