Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Kea
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
446
Issues
446
List
Boards
Labels
Service Desk
Milestones
Merge Requests
72
Merge Requests
72
Operations
Operations
Incidents
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
ISC Open Source Projects
Kea
Commits
5eb2ff86
Commit
5eb2ff86
authored
Jan 07, 2013
by
JINMEI Tatuya
Browse files
Options
Browse Files
Download
Plain Diff
[master] Merge branch 'trac2433'
parents
0de32e7f
96f97334
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
785 additions
and
6 deletions
+785
-6
src/lib/dns/Makefile.am
src/lib/dns/Makefile.am
+5
-1
src/lib/dns/dns_fwd.h
src/lib/dns/dns_fwd.h
+64
-0
src/lib/dns/master_loader.cc
src/lib/dns/master_loader.cc
+1
-1
src/lib/dns/master_loader_callbacks.h
src/lib/dns/master_loader_callbacks.h
+3
-3
src/lib/dns/rrcollator.cc
src/lib/dns/rrcollator.cc
+1
-1
src/lib/dns/tests/Makefile.am
src/lib/dns/tests/Makefile.am
+1
-0
src/lib/dns/tests/zone_checker_unittest.cc
src/lib/dns/tests/zone_checker_unittest.cc
+352
-0
src/lib/dns/zone_checker.cc
src/lib/dns/zone_checker.cc
+196
-0
src/lib/dns/zone_checker.h
src/lib/dns/zone_checker.h
+162
-0
No files found.
src/lib/dns/Makefile.am
View file @
5eb2ff86
...
...
@@ -95,6 +95,7 @@ lib_LTLIBRARIES = libb10-dns++.la
libb10_dns___la_LDFLAGS
=
-no-undefined
-version-info
2:0:0
libb10_dns___la_SOURCES
=
libb10_dns___la_SOURCES
+=
dns_fwd.h
libb10_dns___la_SOURCES
+=
edns.h edns.cc
libb10_dns___la_SOURCES
+=
exceptions.h exceptions.cc
libb10_dns___la_SOURCES
+=
master_lexer_inputsource.h master_lexer_inputsource.cc
...
...
@@ -129,6 +130,7 @@ libb10_dns___la_SOURCES += master_loader_callbacks.h master_loader_callbacks.cc
libb10_dns___la_SOURCES
+=
master_loader.h
libb10_dns___la_SOURCES
+=
rrset_collection_base.h
libb10_dns___la_SOURCES
+=
rrset_collection.h rrset_collection.cc
libb10_dns___la_SOURCES
+=
zone_checker.h zone_checker.cc
libb10_dns___la_SOURCES
+=
rdata/generic/detail/char_string.h
libb10_dns___la_SOURCES
+=
rdata/generic/detail/char_string.cc
libb10_dns___la_SOURCES
+=
rdata/generic/detail/nsec_bitmap.h
...
...
@@ -158,6 +160,7 @@ libdns___includedir = $(includedir)/$(PACKAGE_NAME)/dns
libdns___include_HEADERS
=
\
edns.h
\
exceptions.h
\
dns_fwd.h
\
labelsequence.h
\
message.h
\
masterload.h
\
...
...
@@ -175,7 +178,8 @@ libdns___include_HEADERS = \
rrset_collection_base.h
\
rrset_collection.h
\
rrttl.h
\
tsigkey.h
tsigkey.h
\
zone_checker.h
# Purposely not installing these headers:
# name_internal.h: used only internally, and not actually DNS specific
# rdata/*/detail/*.h: these are internal use only
...
...
src/lib/dns/dns_fwd.h
0 → 100644
View file @
5eb2ff86
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef DNS_FWD_H
#define DNS_FWD_H 1
/// \file dns_fwd.h
/// \brief Forward declarations for definitions of libdns++
///
/// This file provides a set of forward declarations for definitions commonly
/// used in libdns++ to help minimize dependency when actual the definition
/// is not necessary.
namespace
isc
{
namespace
dns
{
class
EDNS
;
class
Name
;
class
MasterLoader
;
class
MasterLoaderCallbacks
;
class
Message
;
class
AbstractMessageRenderer
;
class
MessageRenderer
;
class
NSEC3Hash
;
class
NSEC3HashCreator
;
class
Opcode
;
class
Question
;
class
Rcode
;
namespace
rdata
{
class
Rdata
;
}
class
RRCollator
;
class
RRClass
;
class
RRType
;
class
RRTTL
;
class
AbstractRRset
;
class
RdataIterator
;
class
RRsetCollectionBase
;
class
RRsetCollection
;
class
Serial
;
class
TSIGContext
;
class
TSIGError
;
class
TSIGKey
;
class
TSIGKeyRing
;
class
TSIGRecord
;
}
// namespace dns
}
// namespace isc
#endif // DNS_FWD_H
// Local Variables:
// mode: c++
// End:
src/lib/dns/master_loader.cc
View file @
5eb2ff86
...
...
@@ -393,7 +393,7 @@ private:
shared_ptr
<
Name
>
last_name_
;
// Last seen name (for INITAL_WS handling)
const
RRClass
zone_class_
;
MasterLoaderCallbacks
callbacks_
;
AddRRCallback
add_callback_
;
const
AddRRCallback
add_callback_
;
boost
::
scoped_ptr
<
RRTTL
>
default_ttl_
;
// Default TTL of RRs used when
// unspecified. If NULL no default
// is known.
...
...
src/lib/dns/master_loader_callbacks.h
View file @
5eb2ff86
...
...
@@ -100,7 +100,7 @@ public:
/// If the caller of the loader wants to abort, it is possible to throw
/// from the callback, which aborts the load.
void
error
(
const
std
::
string
&
source_name
,
size_t
source_line
,
const
std
::
string
&
reason
)
const
std
::
string
&
reason
)
const
{
error_
(
source_name
,
source_line
,
reason
);
}
...
...
@@ -117,7 +117,7 @@ public:
/// may be false positives), it is possible to throw from inside the
/// callback.
void
warning
(
const
std
::
string
&
source_name
,
size_t
source_line
,
const
std
::
string
&
reason
)
const
std
::
string
&
reason
)
const
{
warning_
(
source_name
,
source_line
,
reason
);
}
...
...
@@ -133,7 +133,7 @@ public:
static
MasterLoaderCallbacks
getNullCallbacks
();
private:
IssueCallback
error_
,
warning_
;
const
IssueCallback
error_
,
warning_
;
};
}
...
...
src/lib/dns/rrcollator.cc
View file @
5eb2ff86
...
...
@@ -42,7 +42,7 @@ public:
const
RdataPtr
&
rdata
);
RRsetPtr
current_rrset_
;
AddRRsetCallback
callback_
;
const
AddRRsetCallback
callback_
;
};
namespace
{
...
...
src/lib/dns/tests/Makefile.am
View file @
5eb2ff86
...
...
@@ -76,6 +76,7 @@ run_unittests_SOURCES += tsigrecord_unittest.cc
run_unittests_SOURCES
+=
character_string_unittest.cc
run_unittests_SOURCES
+=
master_loader_callbacks_test.cc
run_unittests_SOURCES
+=
rrset_collection_unittest.cc
run_unittests_SOURCES
+=
zone_checker_unittest.cc
run_unittests_SOURCES
+=
run_unittests.cc
run_unittests_CPPFLAGS
=
$(AM_CPPFLAGS)
$(GTEST_INCLUDES)
# We shouldn't need to include BOTAN_LIBS here, but there
...
...
src/lib/dns/tests/zone_checker_unittest.cc
0 → 100644
View file @
5eb2ff86
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <dns/zone_checker.h>
#include <exceptions/exceptions.h>
#include <dns/name.h>
#include <dns/rrclass.h>
#include <dns/rrset.h>
#include <dns/rrtype.h>
#include <dns/rrttl.h>
#include <dns/rdataclass.h>
#include <dns/rrset_collection.h>
#include <gtest/gtest.h>
#include <boost/bind.hpp>
#include <boost/scoped_ptr.hpp>
#include <algorithm>
#include <string>
#include <sstream>
#include <vector>
using
isc
::
Unexpected
;
using
namespace
isc
::
dns
;
using
namespace
isc
::
dns
::
rdata
;
namespace
{
const
char
*
const
soa_txt
=
"ns.example.com. root.example.com. 0 0 0 0 0"
;
const
char
*
const
ns_txt1
=
"ns.example.com."
;
const
char
*
const
ns_a_txt1
=
"192.0.2.1"
;
const
char
*
const
ns_txt2
=
"ns2.example.com."
;
const
char
*
const
ns_a_txt2
=
"192.0.2.2"
;
class
ZoneCheckerTest
:
public
::
testing
::
Test
{
protected:
ZoneCheckerTest
()
:
zname_
(
"example.com"
),
zclass_
(
RRClass
::
IN
()),
soa_
(
new
RRset
(
zname_
,
zclass_
,
RRType
::
SOA
(),
RRTTL
(
60
))),
ns_
(
new
RRset
(
zname_
,
zclass_
,
RRType
::
NS
(),
RRTTL
(
60
))),
callbacks_
(
boost
::
bind
(
&
ZoneCheckerTest
::
callback
,
this
,
_1
,
true
),
boost
::
bind
(
&
ZoneCheckerTest
::
callback
,
this
,
_1
,
false
))
{
std
::
stringstream
ss
;
ss
<<
"example.com. 60 IN SOA "
<<
soa_txt
<<
"
\n
"
;
ss
<<
"example.com. 60 IN NS "
<<
ns_txt1
<<
"
\n
"
;
ss
<<
"ns.example.com. 60 IN A "
<<
ns_a_txt1
<<
"
\n
"
;
ss
<<
"ns2.example.com. 60 IN A "
<<
ns_a_txt2
<<
"
\n
"
;
rrsets_
.
reset
(
new
RRsetCollection
(
ss
,
zname_
,
zclass_
));
}
public:
// This one is passed to boost::bind. Some compilers seem to require
// it be public.
void
callback
(
const
std
::
string
&
reason
,
bool
is_error
)
{
if
(
is_error
)
{
errors_
.
push_back
(
reason
);
}
else
{
warns_
.
push_back
(
reason
);
}
}
protected:
// Check stored issue messages with expected ones. Clear vectors so
// the caller can check other cases.
void
checkIssues
()
{
EXPECT_EQ
(
expected_errors_
.
size
(),
errors_
.
size
());
for
(
int
i
=
0
;
i
<
std
::
min
(
expected_errors_
.
size
(),
errors_
.
size
());
++
i
)
{
// The actual message should begin with the expected message.
EXPECT_EQ
(
0
,
errors_
[
0
].
find
(
expected_errors_
[
0
]))
<<
"actual message: "
<<
errors_
[
0
]
<<
" expected: "
<<
expected_errors_
[
0
];
}
EXPECT_EQ
(
expected_warns_
.
size
(),
warns_
.
size
());
for
(
int
i
=
0
;
i
<
std
::
min
(
expected_warns_
.
size
(),
warns_
.
size
());
++
i
)
{
EXPECT_EQ
(
0
,
warns_
[
0
].
find
(
expected_warns_
[
0
]))
<<
"actual message: "
<<
warns_
[
0
]
<<
" expected: "
<<
expected_warns_
[
0
];
}
errors_
.
clear
();
expected_errors_
.
clear
();
warns_
.
clear
();
expected_warns_
.
clear
();
}
const
Name
zname_
;
const
RRClass
zclass_
;
boost
::
scoped_ptr
<
RRsetCollection
>
rrsets_
;
RRsetPtr
soa_
;
RRsetPtr
ns_
;
std
::
vector
<
std
::
string
>
errors_
;
std
::
vector
<
std
::
string
>
warns_
;
std
::
vector
<
std
::
string
>
expected_errors_
;
std
::
vector
<
std
::
string
>
expected_warns_
;
ZoneCheckerCallbacks
callbacks_
;
};
TEST_F
(
ZoneCheckerTest
,
checkGood
)
{
// Checking a valid case. No errors or warnings should be reported.
EXPECT_TRUE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
checkIssues
();
// Multiple NS RRs are okay.
rrsets_
->
removeRRset
(
zname_
,
zclass_
,
RRType
::
NS
());
ns_
->
addRdata
(
generic
::
NS
(
ns_txt1
));
ns_
->
addRdata
(
generic
::
NS
(
ns_txt2
));
rrsets_
->
addRRset
(
ns_
);
EXPECT_TRUE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
checkIssues
();
}
TEST_F
(
ZoneCheckerTest
,
checkSOA
)
{
// If the zone has no SOA it triggers an error.
rrsets_
->
removeRRset
(
zname_
,
zclass_
,
RRType
::
SOA
());
EXPECT_FALSE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
expected_errors_
.
push_back
(
"zone example.com/IN: has 0 SOA records"
);
checkIssues
();
// If null callback is specified, checkZone() only returns the final
// result.
ZoneCheckerCallbacks
noerror_callbacks
(
NULL
,
boost
::
bind
(
&
ZoneCheckerTest
::
callback
,
this
,
_1
,
false
));
EXPECT_FALSE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
noerror_callbacks
));
checkIssues
();
// If there are more than 1 SOA RR, it's also an error.
errors_
.
clear
();
soa_
->
addRdata
(
generic
::
SOA
(
soa_txt
));
soa_
->
addRdata
(
generic
::
SOA
(
"ns2.example.com. . 0 0 0 0 0"
));
rrsets_
->
addRRset
(
soa_
);
EXPECT_FALSE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
expected_errors_
.
push_back
(
"zone example.com/IN: has 2 SOA records"
);
checkIssues
();
// If the SOA RRset is "empty", it's treated as an implementation
// (rather than operational) error and results in an exception.
rrsets_
->
removeRRset
(
zname_
,
zclass_
,
RRType
::
SOA
());
soa_
.
reset
(
new
RRset
(
zname_
,
zclass_
,
RRType
::
SOA
(),
RRTTL
(
60
)));
rrsets_
->
addRRset
(
soa_
);
EXPECT_THROW
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
),
Unexpected
);
checkIssues
();
// no error/warning should be reported
// Likewise, if the SOA RRset contains non SOA Rdata, it should be a bug.
rrsets_
->
removeRRset
(
zname_
,
zclass_
,
RRType
::
SOA
());
soa_
.
reset
(
new
RRset
(
zname_
,
zclass_
,
RRType
::
SOA
(),
RRTTL
(
60
)));
soa_
->
addRdata
(
createRdata
(
RRType
::
NS
(),
zclass_
,
"ns.example.com"
));
rrsets_
->
addRRset
(
soa_
);
EXPECT_THROW
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
),
Unexpected
);
checkIssues
();
// no error/warning should be reported
}
TEST_F
(
ZoneCheckerTest
,
checkNS
)
{
// If the zone has no NS at origin it triggers an error.
rrsets_
->
removeRRset
(
zname_
,
zclass_
,
RRType
::
NS
());
EXPECT_FALSE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
expected_errors_
.
push_back
(
"zone example.com/IN: has no NS records"
);
checkIssues
();
// Check two buggy cases like the SOA tests
ns_
.
reset
(
new
RRset
(
zname_
,
zclass_
,
RRType
::
NS
(),
RRTTL
(
60
)));
rrsets_
->
addRRset
(
ns_
);
EXPECT_THROW
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
),
Unexpected
);
checkIssues
();
// no error/warning should be reported
rrsets_
->
removeRRset
(
zname_
,
zclass_
,
RRType
::
NS
());
ns_
.
reset
(
new
RRset
(
zname_
,
zclass_
,
RRType
::
NS
(),
RRTTL
(
60
)));
ns_
->
addRdata
(
createRdata
(
RRType
::
TXT
(),
zclass_
,
"ns.example.com"
));
rrsets_
->
addRRset
(
ns_
);
EXPECT_THROW
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
),
Unexpected
);
checkIssues
();
// no error/warning should be reported
}
TEST_F
(
ZoneCheckerTest
,
checkNSData
)
{
const
Name
ns_name
(
"ns.example.com"
);
// If a ("in-bailiwick") NS name doesn't have an address record, it's
// reported as a warning.
rrsets_
->
removeRRset
(
ns_name
,
zclass_
,
RRType
::
A
());
EXPECT_TRUE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
expected_warns_
.
push_back
(
"zone example.com/IN: NS has no address"
);
checkIssues
();
// Same check, but disabling warning callback. Same result, but without
// the warning.
ZoneCheckerCallbacks
nowarn_callbacks
(
boost
::
bind
(
&
ZoneCheckerTest
::
callback
,
this
,
_1
,
true
),
NULL
);
EXPECT_TRUE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
nowarn_callbacks
));
checkIssues
();
// A tricky case: if the name matches a wildcard, it should technically
// be considered valid, but this checker doesn't check that far and still
// warns.
RRsetPtr
wild
(
new
RRset
(
Name
(
"*.example.com"
),
zclass_
,
RRType
::
A
(),
RRTTL
(
0
)));
wild
->
addRdata
(
in
::
A
(
"192.0.2.255"
));
rrsets_
->
addRRset
(
wild
);
EXPECT_TRUE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
expected_warns_
.
push_back
(
"zone example.com/IN: NS has no address"
);
checkIssues
();
// If there's a CNAME at the name instead, it's an error.
rrsets_
->
removeRRset
(
Name
(
"*.example.com"
),
zclass_
,
RRType
::
A
());
RRsetPtr
cname
(
new
RRset
(
ns_name
,
zclass_
,
RRType
::
CNAME
(),
RRTTL
(
60
)));
cname
->
addRdata
(
generic
::
CNAME
(
"cname.example.com"
));
rrsets_
->
addRRset
(
cname
);
EXPECT_FALSE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
expected_errors_
.
push_back
(
"zone example.com/IN: NS 'ns.example.com' is "
"a CNAME (illegal per RFC2181)"
);
checkIssues
();
// It doesn't have to be A. An AAAA is enough.
rrsets_
->
removeRRset
(
ns_name
,
zclass_
,
RRType
::
CNAME
());
RRsetPtr
aaaa
(
new
RRset
(
ns_name
,
zclass_
,
RRType
::
AAAA
(),
RRTTL
(
60
)));
aaaa
->
addRdata
(
in
::
AAAA
(
"2001:db8::1"
));
rrsets_
->
addRRset
(
aaaa
);
EXPECT_TRUE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
checkIssues
();
// Coexisting CNAME makes it error (CNAME with other record is itself
// invalid, but it's a different issue in this context)
rrsets_
->
addRRset
(
cname
);
EXPECT_FALSE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
expected_errors_
.
push_back
(
"zone example.com/IN: NS 'ns.example.com' is "
"a CNAME (illegal per RFC2181)"
);
checkIssues
();
// It doesn't matter if the NS name is "out of bailiwick".
rrsets_
->
removeRRset
(
ns_name
,
zclass_
,
RRType
::
CNAME
());
rrsets_
->
removeRRset
(
zname_
,
zclass_
,
RRType
::
NS
());
ns_
.
reset
(
new
RRset
(
zname_
,
zclass_
,
RRType
::
NS
(),
RRTTL
(
60
)));
ns_
->
addRdata
(
generic
::
NS
(
"ns.example.org"
));
rrsets_
->
addRRset
(
ns_
);
EXPECT_TRUE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
checkIssues
();
// Note that if the NS name is the origin name, it should be checked
rrsets_
->
removeRRset
(
zname_
,
zclass_
,
RRType
::
NS
());
ns_
.
reset
(
new
RRset
(
zname_
,
zclass_
,
RRType
::
NS
(),
RRTTL
(
60
)));
ns_
->
addRdata
(
generic
::
NS
(
zname_
));
rrsets_
->
addRRset
(
ns_
);
EXPECT_TRUE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
expected_warns_
.
push_back
(
"zone example.com/IN: NS has no address"
);
checkIssues
();
}
TEST_F
(
ZoneCheckerTest
,
checkNSWithDelegation
)
{
// Tests various cases where there's a zone cut due to delegation between
// the zone origin and the NS name. In each case the NS name doesn't have
// an address record.
const
Name
ns_name
(
"ns.child.example.com"
);
// Zone cut due to delegation in the middle; the check for the address
// record should be skipped.
rrsets_
->
removeRRset
(
zname_
,
zclass_
,
RRType
::
NS
());
ns_
.
reset
(
new
RRset
(
zname_
,
zclass_
,
RRType
::
NS
(),
RRTTL
(
60
)));
ns_
->
addRdata
(
generic
::
NS
(
ns_name
));
rrsets_
->
addRRset
(
ns_
);
RRsetPtr
child_ns
(
new
RRset
(
Name
(
"child.example.com"
),
zclass_
,
RRType
::
NS
(),
RRTTL
(
60
)));
child_ns
->
addRdata
(
generic
::
NS
(
"ns.example.org"
));
rrsets_
->
addRRset
(
child_ns
);
EXPECT_TRUE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
checkIssues
();
// Zone cut at the NS name. Same result.
rrsets_
->
removeRRset
(
child_ns
->
getName
(),
zclass_
,
RRType
::
NS
());
child_ns
.
reset
(
new
RRset
(
ns_name
,
zclass_
,
RRType
::
NS
(),
RRTTL
(
60
)));
child_ns
->
addRdata
(
generic
::
NS
(
"ns.example.org"
));
rrsets_
->
addRRset
(
child_ns
);
EXPECT_TRUE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
checkIssues
();
// Zone cut below the NS name. The check applies.
rrsets_
->
removeRRset
(
child_ns
->
getName
(),
zclass_
,
RRType
::
NS
());
child_ns
.
reset
(
new
RRset
(
Name
(
"another.ns.child.example.com"
),
zclass_
,
RRType
::
NS
(),
RRTTL
(
60
)));
child_ns
->
addRdata
(
generic
::
NS
(
"ns.example.org"
));
rrsets_
->
addRRset
(
child_ns
);
EXPECT_TRUE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
expected_warns_
.
push_back
(
"zone example.com/IN: NS has no address"
);
checkIssues
();
}
TEST_F
(
ZoneCheckerTest
,
checkNSWithDNAME
)
{
// Similar to the above case, but the zone cut is due to DNAME. This is
// an invalid configuration.
const
Name
ns_name
(
"ns.child.example.com"
);
// Zone cut due to DNAME at the zone origin. This is an invalid case.
rrsets_
->
removeRRset
(
zname_
,
zclass_
,
RRType
::
NS
());
ns_
.
reset
(
new
RRset
(
zname_
,
zclass_
,
RRType
::
NS
(),
RRTTL
(
60
)));
ns_
->
addRdata
(
generic
::
NS
(
ns_name
));
rrsets_
->
addRRset
(
ns_
);
RRsetPtr
dname
(
new
RRset
(
zname_
,
zclass_
,
RRType
::
DNAME
(),
RRTTL
(
60
)));
dname
->
addRdata
(
generic
::
DNAME
(
"example.org"
));
rrsets_
->
addRRset
(
dname
);
EXPECT_FALSE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
expected_errors_
.
push_back
(
"zone example.com/IN: NS 'ns.child.example.com'"
" is below a DNAME 'example.com'"
);
checkIssues
();
// Zone cut due to DNAME in the middle. Same result.
rrsets_
->
removeRRset
(
zname_
,
zclass_
,
RRType
::
DNAME
());
dname
.
reset
(
new
RRset
(
Name
(
"child.example.com"
),
zclass_
,
RRType
::
DNAME
(),
RRTTL
(
60
)));
dname
->
addRdata
(
generic
::
DNAME
(
"example.org"
));
rrsets_
->
addRRset
(
dname
);
EXPECT_FALSE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
expected_errors_
.
push_back
(
"zone example.com/IN: NS 'ns.child.example.com'"
" is below a DNAME 'child.example.com'"
);
checkIssues
();
// A tricky case: there's also an NS at the name that has DNAME. It's
// prohibited per RFC6672 so we could say it's "undefined". Nevertheless,
// this implementation prefers the NS and skips further checks.
ns_
.
reset
(
new
RRset
(
Name
(
"child.example.com"
),
zclass_
,
RRType
::
NS
(),
RRTTL
(
60
)));
ns_
->
addRdata
(
generic
::
NS
(
"ns.example.org"
));
rrsets_
->
addRRset
(
ns_
);
EXPECT_TRUE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
checkIssues
();
// Zone cut due to DNAME at the NS name. In this case DNAME doesn't
// affect the NS name, so it should result in "no address record" warning.
rrsets_
->
removeRRset
(
dname
->
getName
(),
zclass_
,
RRType
::
DNAME
());
rrsets_
->
removeRRset
(
ns_
->
getName
(),
zclass_
,
RRType
::
NS
());
dname
.
reset
(
new
RRset
(
ns_name
,
zclass_
,
RRType
::
DNAME
(),
RRTTL
(
60
)));
dname
->
addRdata
(
generic
::
DNAME
(
"example.org"
));
rrsets_
->
addRRset
(
dname
);
EXPECT_TRUE
(
checkZone
(
zname_
,
zclass_
,
*
rrsets_
,
callbacks_
));
expected_warns_
.
push_back
(
"zone example.com/IN: NS has no address"
);
checkIssues
();
}
}
src/lib/dns/zone_checker.cc
0 → 100644
View file @
5eb2ff86
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <dns/zone_checker.h>
#include <dns/name.h>
#include <dns/rdataclass.h>
#include <dns/rrclass.h>
#include <dns/rrtype.h>
#include <dns/rrset.h>
#include <dns/rrset_collection_base.h>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <string>
using
boost
::
lexical_cast
;
using
std
::
string
;
namespace
isc
{
namespace
dns
{
namespace
{
std
::
string
zoneText
(
const
Name
&
zone_name
,
const
RRClass
&
zone_class
)
{
return
(
zone_name
.
toText
(
true
)
+
"/"
+
zone_class
.
toText
());
}
void
checkSOA
(
const
Name
&
zone_name
,
const
RRClass
&
zone_class
,
const
RRsetCollectionBase
&
zone_rrsets
,
ZoneCheckerCallbacks
&
callback
)
{
ConstRRsetPtr
rrset
=
zone_rrsets
.
find
(
zone_name
,
zone_class
,
RRType
::
SOA
());
size_t
count
=
0
;
if
(
rrset
)
{
for
(
RdataIteratorPtr
rit
=
rrset
->
getRdataIterator
();
!
rit
->
isLast
();
rit
->
next
(),
++
count
)
{
if
(
dynamic_cast
<
const
rdata
::
generic
::
SOA
*>
(
&
rit
->
getCurrent
())
==
NULL
)
{
isc_throw
(
Unexpected
,
"Zone checker found bad RDATA in SOA"
);
}
}
if
(
count
==
0
)
{
// this should be an implementation bug, not an operational error.
isc_throw
(
Unexpected
,
"Zone checker found an empty SOA RRset"
);
}
}
if
(
count
!=
1
)
{
callback
.
error
(
"zone "
+
zoneText
(
zone_name
,
zone_class
)
+
": has "
+
lexical_cast
<
string
>
(
count
)
+
" SOA records"
);
}
}
// Check if a target name is beyond zone cut, either due to delegation or
// DNAME. Note that DNAME works on the origin but not on the name itself,
// while delegation works on the name itself (but the NS at the origin is not
// delegation).
ConstRRsetPtr
findZoneCut
(
const
Name
&
zone_name
,
const
RRClass
&
zone_class
,
const
RRsetCollectionBase
&
zone_rrsets
,
const
Name
&
target_name
)
{
const
unsigned
int
origin_count
=
zone_name
.
getLabelCount
();
const
unsigned
int
target_count
=
target_name
.
getLabelCount
();
assert
(
origin_count
<=
target_count
);
for
(
unsigned
int
l
=
origin_count
;
l
<=
target_count
;
++
l
)
{
const
Name
&
mid_name
=
(
l
==
target_count
)
?
target_name
:
target_name
.
split
(
target_count
-
l
);
ConstRRsetPtr
found
;
if
(
l
!=
origin_count
&&
(
found
=
zone_rrsets
.
find
(
mid_name
,
zone_class
,
RRType
::
NS
()))
!=
NULL
)
{
return
(
found
);
}
if
(
l
!=
target_count
&&
(
found
=
zone_rrsets
.
find
(
mid_name
,
zone_class
,
RRType
::
DNAME
()))
!=
NULL
)
{
return
(
found
);
}
}
return
(
ConstRRsetPtr
());
}
// Check if each "in-zone" NS name has an address record, identifying some
// err