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