18 #include <boost/bind.hpp>
19 #include <boost/lexical_cast.hpp>
23 using boost::lexical_cast;
31 zoneText(
const Name& zone_name,
const RRClass& zone_class) {
32 return (zone_name.toText(
true) +
"/" + zone_class.toText());
36 checkSOA(
const Name& zone_name,
const RRClass& zone_class,
37 const RRsetCollectionBase& zone_rrsets,
38 ZoneCheckerCallbacks& callback) {
40 zone_rrsets.find(zone_name, zone_class,
RRType::SOA());
45 rit->next(), ++count) {
46 if (
dynamic_cast<const rdata::generic::SOA*
>(&rit->getCurrent()) ==
48 isc_throw(Unexpected,
"Zone checker found bad RDATA in SOA");
53 isc_throw(Unexpected,
"Zone checker found an empty SOA RRset");
57 callback.error(
"zone " + zoneText(zone_name, zone_class) +
": has " +
58 lexical_cast<string>(count) +
" SOA records");
67 findZoneCut(
const Name& zone_name,
const RRClass& zone_class,
68 const RRsetCollectionBase& zone_rrsets,
const Name& target_name) {
69 const unsigned int origin_count = zone_name.getLabelCount();
70 const unsigned int target_count = target_name.getLabelCount();
71 assert(origin_count <= target_count);
73 for (
unsigned int l = origin_count; l <= target_count; ++l) {
74 const Name& mid_name = (l == target_count) ? target_name :
75 target_name.split(target_count - l);
78 if (l != origin_count &&
79 (found = zone_rrsets.find(mid_name, zone_class,
RRType::NS())) !=
83 if (l != target_count &&
84 (found = zone_rrsets.find(mid_name, zone_class,
RRType::DNAME()))
95 checkNSNames(
const Name& zone_name,
const RRClass& zone_class,
96 const RRsetCollectionBase& zone_rrsets,
98 if (ns_rrset->getRdataCount() == 0) {
100 isc_throw(Unexpected,
"Zone checker found an empty NS RRset");
106 const rdata::generic::NS* ns_data =
107 dynamic_cast<const rdata::generic::NS*
>(&rit->getCurrent());
108 if (ns_data == NULL) {
109 isc_throw(Unexpected,
"Zone checker found bad RDATA in NS");
111 const Name& ns_name = ns_data->getNSName();
113 ns_name.compare(zone_name).getRelation();
121 zone_rrsets, ns_name);
126 callbacks.error(
"zone " + zoneText(zone_name, zone_class) +
127 ": NS '" + ns_name.toText(
true) +
"' is " +
129 cut_rrset->getName().toText(
true) +
130 "' (illegal per RFC6672)");
136 if (zone_rrsets.find(ns_name, zone_class,
RRType::CNAME()) != NULL) {
137 callbacks.error(
"zone " + zoneText(zone_name, zone_class) +
138 ": NS '" + ns_name.toText(
true) +
"' is a CNAME " +
139 "(illegal per RFC2181)");
142 if (zone_rrsets.find(ns_name, zone_class,
RRType::A()) == NULL &&
143 zone_rrsets.find(ns_name, zone_class,
RRType::AAAA()) == NULL) {
144 callbacks.warn(
"zone " + zoneText(zone_name, zone_class) +
145 ": NS has no address records (A or AAAA)");
151 checkNS(
const Name& zone_name,
const RRClass& zone_class,
152 const RRsetCollectionBase& zone_rrsets,
153 ZoneCheckerCallbacks& callbacks) {
155 zone_rrsets.find(zone_name, zone_class,
RRType::NS());
157 callbacks.error(
"zone " + zoneText(zone_name, zone_class) +
158 ": has no NS records");
161 checkNSNames(zone_name, zone_class, zone_rrsets, rrset, callbacks);
167 errorWrapper(
const string& reason,
const ZoneCheckerCallbacks* callbacks,
170 callbacks->error(reason);
178 bool had_error =
false;
180 boost::bind(errorWrapper, _1, &callbacks, &had_error),
183 checkSOA(zone_name, zone_class, zone_rrsets, my_callbacks);
184 checkNS(zone_name, zone_class, zone_rrsets, my_callbacks);