Commit ce7db48d authored by Stephen Morris's avatar Stephen Morris
Browse files

[2404] Merge branch 'master' into trac2404

parents 1c59115d 126aeb9d
517. [func] stephen
Added IOAddress::toBytes() to get byte representation of address.
Also added convenience methods for V4/V6 address determination.
(Trac #2396, git c23f87e8ac3ea781b38d688f8f7b58539f85e35a)
516. [bug] marcin
Fixed 'make distcheck' failure when running perfdhcp unit tests.
The unit tests used to read files from the folder specified
with the path relative to current folder, thus when the test was
run from a different folder the files could not be found.
(Trac #2479, git 4e8325e1b309f1d388a3055ec1e1df98c377f383)
515. [bug] jinmei
The in-memory data source now accepts an RRSIG provided without
a covered RRset in loading. A subsequent query for its owner name
of the covered type would generally result in NXRRSET; if the
covered RRset is of type NSEC3, the corresponding NSEC3 processing
would result in SERVFAIL.
(Trac #2420, git 6744c100953f6def5500bcb4bfc330b9ffba0f5f)
514. [bug] jelte
b10-msgq now handles socket errors more gracefully when sending data
to clients. It no longer exits with 'broken pipe' errors, and is
also better at resending data on temporary error codes from send().
(Trac #2398, git 9f6b45ee210a253dca608848a58c824ff5e0d234)
513. [func] marcin
Implemented the OptionCustom class for DHCPv4 and DHCPv6.
This class represents an option which has a defined
structure: a set of data fields of specific types and order.
It is used to represent those options that can't be
represented by any other specialized class.
(Trac #2312, git 28d885b457dda970d9aecc5de018ec1120143a10)
512. [func] jelte
Added a new tool b10-certgen, to check and update the self-signed
SSL certificate used by b10-cmdctl. The original certificate
provided has been removed, and a fresh one is generated upon first
build. See the b10-certgen manpage for information on how to update
existing installed certificates.
(Trac #1044, git 510773dd9057ccf6caa8241e74a7a0b34ca971ab)
511. [bug] stephen
Fixed a race condition in the DHCP tests whereby the test program
spawned a subprocess and attempted to read (without waiting) from
the interconnecting pipe before the subprocess had written
anything. The lack of output was being interpreted as a test
failure.
(Trac #2410, git f53e65cdceeb8e6da4723730e4ed0a17e4646579)
510. [func] marcin
DHCP option instances can be created using a collection of strings.
Each string represents a value of a particular data field within
an option. The data field values, given as strings, are validated
against the actual types of option fields specified in the options
definitions.
(Trac #2490, git 56cfd6612fcaeae9acec4a94e1e5f1a88142c44d)
509. [func] muks
Log messages now include the pid of the process that logged the
message.
(Trac #1745, git fc8bbf3d438e8154e7c2bdd322145a7f7854dc6a)
508. [bug] stephen
Split the DHCP library into two directories, each with its own
Makefile. This properly solves the problem whereby a "make"
......
......@@ -20,6 +20,13 @@ dist_doc_DATA = AUTHORS COPYING ChangeLog README
.PHONY: check-valgrind check-valgrind-suppress
install-exec-hook:
-@echo -e "\033[1;33m" # switch to yellow color text
@echo "NOTE: BIND 10 does not automatically start DNS services when it is run"
@echo " in its default configuration. Please see the Guide for information"
@echo " on how to configure these services to be started automatically."
-@echo -e "\033[m" # switch back to normal
check-valgrind:
if HAVE_VALGRIND
@VALGRIND_COMMAND="$(VALGRIND) -q --gen-suppressions=all --track-origins=yes --num-callers=48 --leak-check=full --fullpath-after=" \
......
......@@ -58,5 +58,7 @@ For operating system specific tips see the wiki at:
Please see the wiki and the doc/ directory for various documentation.
The BIND 10 suite is started by running "bind10". Note that the
default configuration does not run any DNS or DHCP servers.
The BIND 10 suite is started by running "bind10". Note that the default
configuration does not start any DNS or DHCP services. Please see the
Guide for information on how to configure these services to be started
automatically.
......@@ -705,7 +705,6 @@ fi
AC_SUBST(BOTAN_LDFLAGS)
AC_SUBST(BOTAN_LIBS)
AC_SUBST(BOTAN_INCLUDES)
# Even though chances are high we already performed a real compilation check
# in the search for the right (pkg)config data, we try again here, to
# be sure.
......@@ -1309,7 +1308,7 @@ AC_CONFIG_FILES([Makefile
tests/tools/badpacket/tests/Makefile
tests/tools/perfdhcp/Makefile
tests/tools/perfdhcp/tests/Makefile
tests/tools/perfdhcp/templates/Makefile
tests/tools/perfdhcp/tests/testdata/Makefile
dns++.pc
])
AC_OUTPUT([doc/version.ent
......
......@@ -425,11 +425,12 @@ var/
</listitem>
<listitem>
<para>In another console, enable the authoritative DNS service
(by using the <command>bindctl</command> utility to configure
the <command>b10-auth</command> component to run):
<screen>$ <userinput>bindctl</userinput></screen>
(Login with the provided default username and password.)
<para>DNS and DHCP components are not started in the default
configuration. In another console, enable the authoritative
DNS service (by using the <command>bindctl</command> utility
to configure the <command>b10-auth</command> component to
run): <screen>$ <userinput>bindctl</userinput></screen>
(Login with the provided default username and password.)
<screen>
&gt; <userinput>config add Boss/components b10-auth</userinput>
&gt; <userinput>config set Boss/components/b10-auth/special auth</userinput>
......@@ -471,7 +472,7 @@ var/
<title>Packages</title>
<para>
Some operating systems or softare package vendors may
Some operating systems or software package vendors may
provide ready-to-use, pre-built software packages for
the BIND 10 suite.
Installing a pre-built package means you do not need to
......@@ -783,7 +784,24 @@ as a dependency earlier -->
<note>
<para>The install step may require superuser privileges.</para>
</note>
<para>
If required, run <command>ldconfig</command> as root with
<filename>/usr/local/lib</filename> (or with ${prefix}/lib if
configured with --prefix) in
<filename>/etc/ld.so.conf</filename> (or the relevant linker
cache configuration file for your OS):
<screen>$ <userinput>ldconfig</userinput></screen>
</para>
<note>
<para>
If you do not run <command>ldconfig</command> where it is
required, you may see errors like the following:
<screen>
program: error while loading shared libraries: libb10-something.so.1:
cannot open shared object file: No such file or directory
</screen>
</para>
</note>
</section>
<!-- TODO: tests -->
......@@ -2139,7 +2157,7 @@ AND_MATCH := "ALL": [ RULE_RAW, RULE_RAW, ... ]
you indicate that the system is not usable without the
component and if such component fails, the system shuts
down no matter when the failure happened. This is the
behaviour of the core components (the ones you can't turn
behavior of the core components (the ones you can't turn
off), but you can declare any other components as core as
well if you wish (but you can turn these off, they just
can't fail).
......
......@@ -225,7 +225,7 @@ createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
message.setHeaderFlag(Message::HEADERFLAG_AA);
RRsetPtr rrset_version = RRsetPtr(new RRset(version_name, RRClass::CH(),
RRType::TXT(), RRTTL(0)));
rrset_version->addRdata(generic::TXT(PACKAGE_STRING));
rrset_version->addRdata(generic::TXT("\"" PACKAGE_STRING "\""));
message.addRRset(Message::SECTION_ANSWER, rrset_version);
RRsetPtr rrset_version_ns = RRsetPtr(new RRset(apex_name, RRClass::CH(),
......
......@@ -364,16 +364,24 @@ class TestConfigCommands(unittest.TestCase):
socket_err_output = io.StringIO()
sys.stdout = socket_err_output
self.assertEqual(1, self.tool.run())
self.assertEqual("Failed to send request, the connection is closed\n",
socket_err_output.getvalue())
# First few lines may be some kind of heading, or a warning that
# Python readline is unavailable, so we do a sub-string check.
self.assertIn("Failed to send request, the connection is closed",
socket_err_output.getvalue())
socket_err_output.close()
# validate log message for http.client.CannotSendRequest
cannot_send_output = io.StringIO()
sys.stdout = cannot_send_output
self.assertEqual(1, self.tool.run())
self.assertEqual("Can not send request, the connection is busy\n",
cannot_send_output.getvalue())
# First few lines may be some kind of heading, or a warning that
# Python readline is unavailable, so we do a sub-string check.
self.assertIn("Can not send request, the connection is busy",
cannot_send_output.getvalue())
cannot_send_output.close()
def test_apply_cfg_command_int(self):
......
/b10-certgen
/b10-certgen.1
/b10-cmdctl
/b10-cmdctl.8
/cmdctl-certfile.pem
/cmdctl-keyfile.pem
/cmdctl.py
/cmdctl.spec
/cmdctl.spec.pre
/run_b10-cmdctl.sh
/b10-cmdctl.8
......@@ -4,6 +4,8 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@
pkglibexec_SCRIPTS = b10-cmdctl
bin_PROGRAMS = b10-certgen
nodist_pylogmessage_PYTHON = $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.py
pylogmessagedir = $(pyexecdir)/isc/log_messages/
......@@ -25,15 +27,18 @@ CLEANFILES= b10-cmdctl cmdctl.pyc cmdctl.spec
CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.py
CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.pyc
man_MANS = b10-cmdctl.8
DISTCLEANFILES = $(man_MANS)
EXTRA_DIST += $(man_MANS) b10-cmdctl.xml cmdctl_messages.mes
man_MANS = b10-cmdctl.8 b10-certgen.1
DISTCLEANFILES = $(man_MANS) cmdctl-certfile.pem cmdctl-keyfile.pem
EXTRA_DIST += $(man_MANS) b10-certgen.xml b10-cmdctl.xml cmdctl_messages.mes
if GENERATE_DOCS
b10-cmdctl.8: b10-cmdctl.xml
@XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-cmdctl.xml
b10-certgen.1: b10-certgen.xml
@XSLTPROC@ --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-certgen.xml
else
$(man_MANS):
......@@ -54,12 +59,23 @@ b10-cmdctl: cmdctl.py $(PYTHON_LOGMSGPKG_DIR)/work/cmdctl_messages.py
$(SED) "s|@@PYTHONPATH@@|@pyexecdir@|" cmdctl.py >$@
chmod a+x $@
b10_certgen_SOURCES = b10-certgen.cc
b10_certgen_CXXFLAGS = $(BOTAN_INCLUDES)
b10_certgen_LDFLAGS = $(BOTAN_LIBS)
# Generate the initial certificates immediately
cmdctl-certfile.pem: b10-certgen
./b10-certgen -q -w
cmdctl-keyfile.pem: b10-certgen
./b10-certgen -q -w
if INSTALL_CONFIGURATIONS
# Below we intentionally use ${INSTALL} -m 640 instead of $(INSTALL_DATA)
# because these file will contain sensitive information.
install-data-local:
$(mkinstalldirs) $(DESTDIR)/@sysconfdir@/@PACKAGE@
$(mkinstalldirs) $(DESTDIR)/@sysconfdir@/@PACKAGE@
for f in $(CMDCTL_CONFIGURATIONS) ; do \
if test ! -f $(DESTDIR)$(sysconfdir)/@PACKAGE@/$$f; then \
${INSTALL} -m 640 $(srcdir)/$$f $(DESTDIR)$(sysconfdir)/@PACKAGE@/ ; \
......
// 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 <botan/botan.h>
#include <botan/x509self.h>
#include <botan/x509stor.h>
#include <botan/rsa.h>
#include <botan/dsa.h>
#include <botan/data_src.h>
using namespace Botan;
#include <iostream>
#include <fstream>
#include <memory>
#include <getopt.h>
// For cleaner 'does not exist or is not readable' output than
// botan provides
#include <unistd.h>
#include <errno.h>
// This is a simple tool that creates a self-signed PEM certificate
// for use with BIND 10. It creates a simple certificate for initial
// setup. Currently, all values are hardcoded defaults. For future
// versions, we may want to add more options for administrators.
// It will create a PEM file containing a certificate with the following
// values:
// common name: localhost
// organization: BIND10
// country code: US
// Additional error return codes; these are specifically
// chosen to be distinct from validation error codes as
// provided by Botan. Their main use is to distinguish
// error cases in the unit tests.
const int DECODING_ERROR = 100;
const int BAD_OPTIONS = 101;
const int READ_ERROR = 102;
const int WRITE_ERROR = 103;
const int UNKNOWN_ERROR = 104;
const int NO_SUCH_FILE = 105;
const int FILE_PERMISSION_ERROR = 106;
void
usage() {
std::cout << "Usage: b10-certgen [OPTION]..." << std::endl;
std::cout << "Validate, create, or update a self-signed certificate for "
"use with b10-cmdctl" << std::endl;
std::cout << "" << std::endl;
std::cout << "Options:" << std::endl;
std::cout << "-c, --certfile=FILE\t\tfile to read or store the certificate"
<< std::endl;
std::cout << "-f, --force\t\t\toverwrite existing certficate even if it"
<< std::endl <<"\t\t\t\tis valid" << std::endl;
std::cout << "-h, --help\t\t\tshow this help" << std::endl;
std::cout << "-k, --keyfile=FILE\t\tfile to store the generated private key"
<< std::endl;
std::cout << "-w, --write\t\t\tcreate a new certificate if the given file"
<< std::endl << "\t\t\t\tdoes not exist, or if is is not valid"
<< std::endl;
std::cout << "-q, --quiet\t\t\tprint no output when creating or validating"
<< std::endl;
}
/// \brief Returns true if the given file exists
///
/// \param filename The file to check
/// \return true if file exists
bool
fileExists(const std::string& filename) {
return (access(filename.c_str(), F_OK) == 0);
}
/// \brief Returns true if the given file exists and is readable
///
/// \param filename The file to check
/// \return true if file exists and is readable
bool
fileIsReadable(const std::string& filename) {
return (access(filename.c_str(), R_OK) == 0);
}
/// \brief Returns true if the given file exists and is writable
///
/// \param filename The file to check
/// \return true if file exists and is writable
bool
fileIsWritable(const std::string& filename) {
return (access(filename.c_str(), W_OK) == 0);
}
/// \brief Helper function for readable error output;
///
/// Returns string representation of X509 result code
/// This does not appear to be provided by Botan itself
///
/// \param code An \c X509_Code instance
/// \return A human-readable c string
const char*
X509CodeToString(const X509_Code& code) {
// note that this list provides more than we would
// need in this context, it is just the enum from
// the source code of Botan.
switch (code) {
case VERIFIED:
return ("verified");
case UNKNOWN_X509_ERROR:
return ("unknown x509 error");
case CANNOT_ESTABLISH_TRUST:
return ("cannot establish trust");
case CERT_CHAIN_TOO_LONG:
return ("certificate chain too long");
case SIGNATURE_ERROR:
return ("signature error");
case POLICY_ERROR:
return ("policy error");
case INVALID_USAGE:
return ("invalid usage");
case CERT_FORMAT_ERROR:
return ("certificate format error");
case CERT_ISSUER_NOT_FOUND:
return ("certificate issuer not found");
case CERT_NOT_YET_VALID:
return ("certificate not yet valid");
case CERT_HAS_EXPIRED:
return ("certificate has expired");
case CERT_IS_REVOKED:
return ("certificate has been revoked");
case CRL_FORMAT_ERROR:
return ("crl format error");
case CRL_NOT_YET_VALID:
return ("crl not yet valid");
case CRL_HAS_EXPIRED:
return ("crl has expired");
case CA_CERT_CANNOT_SIGN:
return ("CA cert cannot sign");
case CA_CERT_NOT_FOR_CERT_ISSUER:
return ("CA certificate not for certificate issuer");
case CA_CERT_NOT_FOR_CRL_ISSUER:
return ("CA certificate not for crl issuer");
default:
return ("Unknown X509 code");
}
}
class CertificateTool {
public:
CertificateTool(bool quiet) : quiet_(quiet) {}
int
createKeyAndCertificate(const std::string& key_file_name,
const std::string& cert_file_name) {
try {
AutoSeeded_RNG rng;
// Create and store a private key
print("Creating key file " + key_file_name);
RSA_PrivateKey key(rng, 2048);
std::ofstream key_file(key_file_name.c_str());
if (!key_file.good()) {
print(std::string("Error writing to ") + key_file_name +
": " + std::strerror(errno));
return (WRITE_ERROR);
}
key_file << PKCS8::PEM_encode(key, rng, "");
if (!key_file.good()) {
print(std::string("Error writing to ") + key_file_name +
": " + std::strerror(errno));
return (WRITE_ERROR);
}
key_file.close();
// Certificate options, currently hardcoded.
// For a future version we may want to make these
// settable.
X509_Cert_Options opts;
opts.common_name = "localhost";
opts.organization = "UNKNOWN";
opts.country = "XX";
opts.CA_key();
print("Creating certificate file " + cert_file_name);
// The exact call changed aftert 1.8, adding the
// hash function option
#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,0)
X509_Certificate cert =
X509::create_self_signed_cert(opts, key, "SHA-256", rng);
#else
X509_Certificate cert =
X509::create_self_signed_cert(opts, key, rng);
#endif
std::ofstream cert_file(cert_file_name.c_str());
if (!cert_file.good()) {
print(std::string("Error writing to ") + cert_file_name +
": " + std::strerror(errno));
return (WRITE_ERROR);
}
cert_file << cert.PEM_encode();
if (!cert_file.good()) {
print(std::string("Error writing to ") + cert_file_name +
": " + std::strerror(errno));
return (WRITE_ERROR);
}
cert_file.close();
} catch(std::exception& e) {
std::cout << "Error creating key or certificate: " << e.what()
<< std::endl;
return (UNKNOWN_ERROR);
}
return (0);
}
int
validateCertificate(const std::string& certfile) {
// Since we are dealing with a self-signed certificate here, we
// also use the certificate to check itself; i.e. we add it
// as a trusted certificate, then validate the certficate itself.
//const X509_Certificate cert(certfile);
try {
X509_Store store;
DataSource_Stream in(certfile);
store.add_trusted_certs(in);
const X509_Code result = store.validate_cert(certfile);
if (result == VERIFIED) {
print(certfile + " is valid");
} else {
print(certfile + " failed to verify: " +
X509CodeToString(result));
}
return (result);
} catch (const Botan::Decoding_Error& bde) {
print(certfile + " failed to verify: " + bde.what());
return (DECODING_ERROR);
} catch (const Botan::Stream_IO_Error& bsie) {
print(certfile + " not read: " + bsie.what());
return (READ_ERROR);
}
}
/// \brief Runs the tool
///
/// \param create_cert Create certificate if true, validate if false.
/// Does nothing if certificate exists and is valid.
/// \param force_create Create new certificate even if it is valid.
/// \param certfile Certificate file to read to or write from.
/// \param keyfile Key file to write if certificate is created.
/// Ignored if create_cert is false
/// \return zero on success, non-zero on failure
int
run(bool create_cert, bool force_create, const std::string& certfile,
const std::string& keyfile)
{
if (create_cert) {
// Unless force is given, only create it if the current
// one is not OK
// First do some basic permission checks; both files
// should either not exist, or be both readable
// and writable
// The checks are done one by one so all errors can
// be enumerated in one go
if (fileExists(certfile)) {
if (!fileIsReadable(certfile)) {
print(certfile + " not readable: " + std::strerror(errno));
create_cert = false;
}
if (!fileIsWritable(certfile)) {
print(certfile + " not writable: " + std::strerror(errno));
create_cert = false;
}
}
// The key file really only needs write permissions (for
// b10-certgen that is)
if (fileExists(keyfile)) {
if (!fileIsWritable(keyfile)) {
print(keyfile + " not writable: " + std::strerror(errno));
create_cert = false;
}
}
if (!create_cert) {
print("Not creating new certificate, "
"check file permissions");
return (FILE_PERMISSION_ERROR);
}
// If we reach this, we know that if they exist, we can both
// read and write them, so now it's up to content checking
// and/or force_create
if (force_create || !fileExists(certfile) ||
validateCertificate(certfile) != VERIFIED) {
return (createKeyAndCertificate(keyfile, certfile));
} else {
print("Not creating a new certificate (use -f to force)");
}
} else {
if (!fileExists(certfile)) {
print(certfile + ": " + std::strerror(errno));
return (NO_SUCH_FILE);
}
if (!fileIsReadable(certfile)) {
print(certfile + " not readable: " + std::strerror(errno));
return (FILE_PERMISSION_ERROR);
}
int result = validateCertificate(certfile);
if (result != 0) {
print("Running with -w would overwrite the certificate");
}
return (result);
}
return (0);
}
private:
/// Prints the message to stdout unless quiet_ is true
void print(const std::string& msg) {
if (!quiet_) {
std::cout << msg << std::endl;
}
}
bool quiet_;
};
int