Commit 73225355 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[master] Merge branch 'master' into trac3336

parents 58e62353 83816e00
788. [func] tomek
DHCPv4 server: New parameter added to configure.ac: --with-kea-config.
It allows selecting configuration backend and accepts one of two
values: BUNDY, which uses Bundy (former BIND10) framework as Kea
0.8 did, or JSON, which reads configuration from a JSON file.
(Trac #3399, git 6e4dd3ae58c091ba0fd64c87fa8d7c268210f99b)
787. [func] marcin
DHCPv6 server: Implemented dynamic reconfiguration of the server,
triggered when the SIGHUP signal is received by the server's
process. Also, server performs a graceful shut down when SIGINT
or SIGTERM signal is received.
(Trac #3406, git 3be60fa6ac521aecae6ae92d26dc03792bc76903)
786. [func] tmark
DHCP-DDNS now supports DDNS updates with TSIG. Please refer to the
Kea Guide for details. Prior to this TSIG keys could be defined but
were not used.
(Trac #3432, git 80fea12a53d1e832d4e7b710ca6ea613300f73ea)
785. [bug] marcin
DHCPv6 server avoids collisions between prefixes that are allocated
as a result of receiving hints from the clients. Previously the
......@@ -18,7 +38,7 @@
(Trac #3268, git bd60252e679f19b062f61926647f661ab169f21c)
783. [func]* tomek
b10-dhcp6: New parameter added to configure: --with-kea-config.
DHCPv6 server: New parameter added to configure: --with-kea-config.
It allows selecting configuration backend and accepts one of two
values: BUNDY, which uses Bundy (former BIND10 framework as Kea
0.8 did, or JSON, which reads configuration from a JSON file.
......
......@@ -55,6 +55,7 @@
* - @subpage dhcpv4OptionsParse
* - @subpage dhcpv4DDNSIntegration
* - @subpage dhcpv4Classifier
* - @subpage dhcpv4ConfigBackend
* - @subpage dhcpv4Other
* - @subpage dhcp6
* - @subpage dhcpv6Session
......@@ -64,6 +65,7 @@
* - @subpage dhcpv6OptionsParse
* - @subpage dhcpv6Classifier
* - @subpage dhcpv6ConfigBackend
* - @subpage dhcpv6SignalBasedReconfiguration
* - @subpage dhcpv6Other
* - @subpage d2
* - @subpage d2CPL
......
# This is an example configuration file for DHCPv4 server in Kea.
# It's a basic scenario with three IPv4 subnets configured. In each
# subnet, there's a smaller pool of dynamic addresses.
{ "Dhcp4":
{
# Kea is told to listen on eth0 interface only.
"interfaces": [ "eth0" ],
# We need to specify lease type. As of May 2014, three backends are supported:
# memfile, mysql and pgsql. We'll just use memfile, because it doesn't require
# any prior set up.
"lease-database": {
"type": "memfile"
},
# Addresses will be assigned with the valid lifetimes being 4000.
# Client is told to start renewing after 1000 seconds. If the server
# does not repond after 2000 seconds since the lease was granted, client
# is supposed to start REBIND procedure (emergency renewal that allows
# switching to a different server).
"valid-lifetime": 4000,
"renew-timer": 1000,
"rebind-timer": 2000,
# The following list defines subnets. Each subnet consists of at
# least subnet and pool entries.
"subnet4": [
{ "pool": [ "192.0.2.1 - 192.0.2.200" ],
"subnet": "192.0.2.0/24" },
{ "pool": [ "192.0.3.100 - 192.0.3.200" ],
"subnet": "192.0.3.0/24" },
{ "pool": [ "192.0.4.1 - 192.0.4.254" ],
"subnet": "192.0.4.0/24" } ]
}
}
# This is an example configuration file for the DHCPv4 server in Kea.
# It is a basic scenario with one IPv4 subnet configured. The subnet
# contains a single pool of dynamically allocated addresses.
{ "Dhcp4":
{
# Kea is told to listen on eth0 interface only.
"interfaces": [ "eth0" ],
# We need to specify lease type. As of May 2014, three backends are supported:
# memfile, mysql and pgsql. We'll just use memfile, because it doesn't require
# any prior set up.
"lease-database": {
"type": "memfile"
},
# Addresses will be assigned with valid lifetimes being 4000. Client
# is told to start renewing after 1000 seconds. If the server does not respond
# after 2000 seconds since the lease was granted, client is supposed
# to start REBIND procedure (emergency renewal that allows switching
# to a different server).
"valid-lifetime": 4000,
"renew-timer": 1000,
"rebind-timer": 2000,
# The following list defines subnets. We have only one subnet
# here.
"subnet4": [
{ "pool": [ "192.0.2.1 - 192.0.2.200" ],
"subnet": "192.0.2.0/24" } ]
}
}
......@@ -5372,75 +5372,118 @@ corresponding values in the DHCP servers' "dhcp-ddns" configuration section.
<section id="d2-tsig-key-list-config">
<title>TSIG Key List</title>
<note>
<simpara>
While this section may be displayed and edited using bindctl, the use
of TSIG in actual communications between D2 and DNS servers is not yet
implemented.
</simpara>
</note>
<para>
DDNS protocol can be conducted with or without TSIG as defined in
RFC 2845. This configuration section allows the administrator to
define the dictionary of TSIG keys to may be used. To use TSIG
when working with a specific DDNS Domain that key must be defined in
the TSIG Key List and referenced by name in that domain's entry in
the DDNS catalog.
</para>
A DDNS protocol exchange can be conducted with or without TSIG
(defined in <ulink url="http://tools.ietf/org/html/rfc2845">RFC
2845</ulink>). This configuration section allows the administrator
to define the set of TSIG keys that may be used in such
exchanges.</para>
<para>To use TSIG when updating entries in a DNS Domain,
a key must be defined in the TSIG Key List and referenced by
name in that domain's configuration entry. When D2 matches a
change request to a domain, it checks whether the domain has
a TSIG key associated with it. If so, D2 will use that key to
sign DNS update messages sent to and verify repsonses received
from the domain's DNS server(s). For each TSIG key required by
the DNS servers that D2 will be working with there must be a
corresponding TSIG key in the TSIG Key list.</para>
<para>
As one might gather from its name, this section is a list of
TSIG keys. Each key has three parameters:
As one might gather from the name, the tsig_key section of the
D2 configuration lists the TSIG keys. Each entry describes a
TSIG key used by one or more DNS servers to authenticate requests
and sign responses. Every entry in the list has three parameters:
<itemizedlist>
<listitem>
<simpara>
<command>name</command> &mdash;
is a unique text label used to identify the this key within the
list. It is this value that is used to specify which key (if any)
should be used with a specific DNS server. So long as it is
unique, its content is arbitrary. It cannot be blank.
a unique text label used to identify this key within the
list. This value is used to specify which key (if any) should be
used when updating a specific domain. So long as it is unique its
content is arbitrary, although for clarity and ease of maintenance
it is recommended that it match the name used on the DNS server(s).
It cannot be blank.
</simpara>
</listitem>
<listitem>
<simpara>
<command>algorithm</command> &mdash;
specifies which hashing algorithm should be used with this
key. This value is not currently used.
key. This value must specify the same algorithm used for the
key on the DNS server(s). The supported algorithms are listed below:
<itemizedlist>
<listitem>
<command>HMAC-MD5</command>
</listitem>
<listitem>
<command>HMAC-SHA1</command>
</listitem>
<listitem>
<command>HMAC-SHA224</command>
</listitem>
<listitem>
<command>HMAC-SHA256</command>
</listitem>
<listitem>
<command>HMAC-SHA384</command>
</listitem>
<listitem>
<command>HMAC-SHA512</command>
</listitem>
</itemizedlist>
This value is not case sensitive.
</simpara>
</listitem>
<listitem>
<simpara>
<command>secret</command> &mdash;
is used to specify the shared secret key code for this key. This
value is not currently used.
is used to specify the shared secret key code for this key. This value is
case sensitive and must exactly match the value specified on the DNS server(s).
It is a base64-encoded text value.
</simpara>
</listitem>
</itemizedlist>
</para>
<para>
As an example, suppose that a domain D2 will be updating is
maintained by a BIND9 DNS server which requires dynamic updates
to be secured with TSIG. Suppose further that the entry for
the TSIG key in BIND9's named.conf file looks like this:
<screen>
:
key "key.four.example.com." {
algorithm hmac-sha224;
secret "bZEG7Ow8OgAUPfLWV3aAUQ==";
};
:
</screen>
By default, the TSIG Key list is empty:
<screen>
<userinput>> config show DhcpDdns/tsig_keys</userinput>
DhcpDdns/tsig_keys [] list (default)
</screen>
To create a new key in the list, one must first add a new key element:
We must first create a new key in the list:
<screen>
<userinput>> config add DhcpDdns/tsig_keys</userinput>
</screen>
Displaying the new element, reveals this:
Displaying the new element, reveals:
<screen>
<userinput>> config show DhcpDdns/tsig_keys[0]</userinput>
DhcpDdns/tsig_keys[0]/name "" string (default)
DhcpDdns/tsig_keys[0]/algorithm "hmac_md5" string (modified)
DhcpDdns/tsig_keys[0]/algorithm "HMAC-MD5" string (modified)
DhcpDdns/tsig_keys[0]/secret "" string (default)
</screen>
Populating the key name and secret, while accepting the default value
for alogorithm:
Now set all three values to match BIND9's key:
<screen>
<userinput>> config set DhcpDdns/tsig_keys[0]/name "key1.example.com"</userinput>
<userinput>> config set DhcpDdns/tsig_keys[0]/secret "123456789"</userinput>
<userinput>> config set DhcpDdns/tsig_keys[0]/name "key.four.example.com"</userinput>
<userinput>> config set DhcpDdns/tsig_keys[0]/algorithm "HMAC-SHA224"</userinput>
<userinput>> config set DhcpDdns/tsig_keys[0]/secret "bZEG7Ow8OgAUPfLWV3aAUQ=="</userinput>
<userinput>> config commit</userinput>
</screen>
</para>
These steps would be repeated for each TSIG key needed. Note that the same TSIG key
can be used with more than one domain.
</section> <!-- "d2-tsig-key-list-config" -->
<section id="d2-forward-ddns-config">
......@@ -5458,8 +5501,6 @@ DhcpDdns/forward_ddns/ddns_domains [] list (default)
</para>
<section id="add-forward-ddns-domain">
<title>Adding Forward DDNS Domains</title>
<para>
A forward DDNS Domain maps a forward DNS zone to a set of DNS servers
which maintain the forward DNS data for that zone. You will need one
......@@ -5638,8 +5679,8 @@ DhcpDdns/reverse_ddns/ddns_domains [] list (default)
<simpara>
<command>key_name</command> &mdash;
If TSIG should be used with this domain's servers, then this
value should be the name of the key from within the TSIG Key List
to use. If the value is blank (the default), TSIG will not be
value should be the name of that key from the TSIG Key List.
If the value is blank (the default), TSIG will not be
used in DDNS conversations with this domain's servers. Currently
this value is not used as TSIG has not been implemented.
</simpara>
......
......@@ -124,15 +124,59 @@ operator<<(std::ostream& os, const D2Params& config) {
}
// *********************** TSIGKeyInfo *************************
// Note these values match correpsonding values for Bind9's
// dnssec-keygen
const char* TSIGKeyInfo::HMAC_MD5_STR = "HMAC-MD5";
const char* TSIGKeyInfo::HMAC_SHA1_STR = "HMAC-SHA1";
const char* TSIGKeyInfo::HMAC_SHA224_STR = "HMAC-SHA224";
const char* TSIGKeyInfo::HMAC_SHA256_STR = "HMAC-SHA256";
const char* TSIGKeyInfo::HMAC_SHA384_STR = "HMAC-SHA384";
const char* TSIGKeyInfo::HMAC_SHA512_STR = "HMAC-SHA512";
TSIGKeyInfo::TSIGKeyInfo(const std::string& name, const std::string& algorithm,
const std::string& secret)
:name_(name), algorithm_(algorithm), secret_(secret) {
:name_(name), algorithm_(algorithm), secret_(secret), tsig_key_() {
remakeKey();
}
TSIGKeyInfo::~TSIGKeyInfo() {
}
const dns::Name&
TSIGKeyInfo::stringToAlgorithmName(const std::string& algorithm_id) {
if (boost::iequals(algorithm_id, HMAC_MD5_STR)) {
return (dns::TSIGKey::HMACMD5_NAME());
} else if (boost::iequals(algorithm_id, HMAC_SHA1_STR)) {
return (dns::TSIGKey::HMACSHA1_NAME());
} else if (boost::iequals(algorithm_id, HMAC_SHA224_STR)) {
return (dns::TSIGKey::HMACSHA224_NAME());
} else if (boost::iequals(algorithm_id, HMAC_SHA256_STR)) {
return (dns::TSIGKey::HMACSHA256_NAME());
} else if (boost::iequals(algorithm_id, HMAC_SHA384_STR)) {
return (dns::TSIGKey::HMACSHA384_NAME());
} else if (boost::iequals(algorithm_id, HMAC_SHA512_STR)) {
return (dns::TSIGKey::HMACSHA512_NAME());
}
isc_throw(BadValue, "Unknown TSIG Key algorithm: " << algorithm_id);
}
void
TSIGKeyInfo::remakeKey() {
try {
// Since our secret value is base64 encoded already, we need to
// build the input string for the appropriate TSIGKey constructor.
// If secret isn't a valid base64 value, the constructor will throw.
std::ostringstream stream;
stream << dns::Name(name_).toText() << ":"
<< secret_ << ":"
<< stringToAlgorithmName(algorithm_);
tsig_key_.reset(new dns::TSIGKey(stream.str()));
} catch (const std::exception& ex) {
isc_throw(D2CfgError, "Cannot make TSIGKey: " << ex.what());
}
}
// *********************** DnsServerInfo *************************
......@@ -164,14 +208,25 @@ operator<<(std::ostream& os, const DnsServerInfo& server) {
// *********************** DdnsDomain *************************
DdnsDomain::DdnsDomain(const std::string& name, const std::string& key_name,
DnsServerInfoStoragePtr servers)
: name_(name), key_name_(key_name), servers_(servers) {
DdnsDomain::DdnsDomain(const std::string& name,
DnsServerInfoStoragePtr servers,
const TSIGKeyInfoPtr& tsig_key_info)
: name_(name), servers_(servers),
tsig_key_info_(tsig_key_info) {
}
DdnsDomain::~DdnsDomain() {
}
const std::string
DdnsDomain::getKeyName() const {
if (tsig_key_info_) {
return (tsig_key_info_->getName());
}
return ("");
}
// *********************** DdnsDomainLstMgr *************************
const char* DdnsDomainListMgr::wildcard_domain_name_ = "*";
......@@ -308,9 +363,6 @@ TSIGKeyInfoParser::build(isc::data::ConstElementPtr key_config) {
local_scalars_.getParam("algorithm", algorithm);
local_scalars_.getParam("secret", secret);
// @todo Validation here is very superficial. This will expand as TSIG
// Key use is more fully implemented.
// Name cannot be blank.
if (name.empty()) {
isc_throw(D2CfgError, "TSIG Key Info must specify name");
......@@ -361,9 +413,6 @@ TSIGKeyInfoParser::createConfigParser(const std::string& config_id) {
void
TSIGKeyInfoParser::commit() {
/// @todo if at some point TSIG keys need some form of runtime resource
/// initialization, such as creating some sort of hash instance in
/// crytpolib. Once TSIG is fully implemented under Trac #3432 we'll know.
}
// *********************** TSIGKeyInfoListParser *************************
......@@ -606,18 +655,26 @@ DdnsDomainParser::build(isc::data::ConstElementPtr domain_config) {
isc_throw(D2CfgError, "Duplicate domain specified:" << name);
}
// Key name is optional. If it is not blank, then validate it against
// the defined list of keys.
// Key name is optional. If it is not blank, then find the key in the
/// list of defined keys.
TSIGKeyInfoPtr tsig_key_info;
local_scalars_.getParam("key_name", key_name, DCfgContextBase::OPTIONAL);
if (!key_name.empty()) {
if ((!keys_) || (keys_->find(key_name) == keys_->end())) {
isc_throw(D2CfgError, "DdnsDomain :" << name <<
" specifies and undefined key:" << key_name);
if (keys_) {
TSIGKeyInfoMap::iterator kit = keys_->find(key_name);
if (kit != keys_->end()) {
tsig_key_info = kit->second;
}
}
if (!tsig_key_info) {
isc_throw(D2CfgError, "DdnsDomain " << name <<
" specifies an undefined key: " << key_name);
}
}
// Instantiate the new domain and add it to domain storage.
DdnsDomainPtr domain(new DdnsDomain(name, key_name, local_servers_));
DdnsDomainPtr domain(new DdnsDomain(name, local_servers_, tsig_key_info));
// Add the new domain to the domain storage.
(*domains_)[name] = domain;
......
......@@ -19,6 +19,7 @@
#include <d2/d2_asio.h>
#include <d2/d_cfg_mgr.h>
#include <dhcpsrv/dhcp_parsers.h>
#include <dns/tsig.h>
#include <exceptions/exceptions.h>
#include <boost/foreach.hpp>
......@@ -264,22 +265,53 @@ typedef boost::shared_ptr<D2Params> D2ParamsPtr;
/// @brief Represents a TSIG Key.
///
/// Currently, this is simple storage class containing the basic attributes of
/// a TSIG Key. It is intended primarily as a reference for working with
/// actual keys and may eventually be replaced by isc::dns::TSIGKey. TSIG Key
/// functionality at this stage is strictly limited to configuration parsing.
/// @todo full functionality for using TSIG during DNS updates will be added
/// in a future release.
/// Acts as both a storage class containing the basic attributes which
/// describe a TSIG Key, as well as owning and providing access to an
/// instance of the actual key (@ref isc::dns::TSIGKey) that can be used
/// by the IO layer for signing and verifying messages.
///
class TSIGKeyInfo {
public:
/// @brief Defines string values for the supported TSIG algorithms
//@{
static const char* HMAC_MD5_STR;
static const char* HMAC_SHA1_STR;
static const char* HMAC_SHA256_STR;
static const char* HMAC_SHA224_STR;
static const char* HMAC_SHA384_STR;
static const char* HMAC_SHA512_STR;
//}@
/// @brief Constructor
///
/// @param name the unique label used to identify this key
/// @param algorithm the name of the encryption alogirthm this key uses.
/// (@todo This will be a fixed list of choices)
///
/// @param secret the secret component of this key
/// @param algorithm the id of the encryption alogirthm this key uses.
/// Currently supported values are (case insensitive):
/// -# "HMAC-MD5"
/// -# "HMAC-SHA1"
/// -# "HMAC-SHA224"
/// -# "HMAC-SHA256"
/// -# "HMAC-SHA384"
/// -# "HMAC-SHA512"
///
/// @param secret The base-64 encoded secret component for this key.
/// (A suitable string for use here could be obtained by running the
/// BIND 9 dnssec-keygen program; the contents of resulting key file
/// will look similar to:
/// @code
/// Private-key-format: v1.3
/// Algorithm: 157 (HMAC_MD5)
/// Key: LSWXnfkKZjdPJI5QxlpnfQ==
/// Bits: AAA=
/// Created: 20140515143700
/// Publish: 20140515143700
/// Activate: 20140515143700
/// @endcode
/// where the value the "Key:" entry is the secret component of the key.)
///
/// @throw D2CfgError if values supplied are invalid:
/// name cannot be blank, algorithm must be a supported value,
/// secret must be a non-blank, base64 encoded string.
TSIGKeyInfo(const std::string& name, const std::string& algorithm,
const std::string& secret);
......@@ -293,7 +325,7 @@ public:
return (name_);
}
/// @brief Getter which returns the key's algorithm.
/// @brief Getter which returns the key's algorithm string ID
///
/// @return returns the algorithm as as std::string.
const std::string getAlgorithm() const {
......@@ -307,18 +339,55 @@ public:
return (secret_);
}
/// @brief Getter which returns the TSIG key used to sign and verify
/// messages
///
/// @return const pointer reference to dns::TSIGKey.
const dns::TSIGKeyPtr& getTSIGKey() const {
return (tsig_key_);
}
/// @brief Converts algorithm id to dns::TSIGKey algorithm dns::Name
///
/// @param algorithm_id string value to translate into an algorithm name.
/// Currently supported values are (case insensitive):
/// -# "HMAC-MD5"
/// -# "HMAC-SHA1"
/// -# "HMAC-SHA224"
/// -# "HMAC-SHA256"
/// -# "HMAC-SHA384"
/// -# "HMAC-SHA512"
///
/// @return const reference to a dns::Name containing the algorithm name
/// @throw BadValue if ID isn't recognized.
static const dns::Name& stringToAlgorithmName(const std::string&
algorithm_id);
private:
/// @brief Creates the actual TSIG key instance member
///
/// Replaces this tsig_key member with a key newly created using the key
/// name, algorithm id, and secret.
/// This method is currently only called by the constructor, however it
/// could be called post-construction should keys ever support expiration.
///
/// @throw D2CfgError with an explanation if the key could not be created.
void remakeKey();
/// @brief The name of the key.
///
/// This value is the unique identifier that domains use to
/// to specify which TSIG key they need.
std::string name_;
/// @brief The algorithm that should be used for this key.
/// @brief The string ID of the algorithm that should be used for this key.
std::string algorithm_;
/// @brief The secret value component of this key.
/// @brief The base64 encoded string secret value component of this key.
std::string secret_;
/// @brief The actual TSIG key.
dns::TSIGKeyPtr tsig_key_;
};
/// @brief Defines a pointer for TSIGKeyInfo instances.
......@@ -454,10 +523,12 @@ public:
/// @brief Constructor
///
/// @param name is the domain name of the domain.
/// @param key_name is the TSIG key name for use with this domain.
/// @param servers is the list of server(s) supporting this domain.
DdnsDomain(const std::string& name, const std::string& key_name,
DnsServerInfoStoragePtr servers);
/// @param tsig_key_info pointer to the TSIGKeyInfo for the dommain's key
/// It defaults to an empty pointer, signifying the domain has no key.
DdnsDomain(const std::string& name,
DnsServerInfoStoragePtr servers,
const TSIGKeyInfoPtr& tsig_key_info = TSIGKeyInfoPtr());
/// @brief Destructor
virtual ~DdnsDomain();
......@@ -469,12 +540,11 @@ public:
return (name_);
}
/// @brief Getter which returns the domain's TSIG key name.
/// @brief Convenience method which returns the domain's TSIG key name.
///
/// @return returns the key name in an std::string.
const std::string getKeyName() const {
return (key_name_);
}
/// @return returns the key name in an std::string. If domain has no
/// TSIG key, the string will empty.
const std::string getKeyName() const;
/// @brief Getter which returns the domain's list of servers.
///
......@@ -483,15 +553,24 @@ public:
return (servers_);
}
/// @brief Getter which returns the domain's TSIGKey info
///
/// @return returns the pointer to the server storage. If the domain
/// is not configured to use TSIG the pointer will be empty.
const TSIGKeyInfoPtr& getTSIGKeyInfo() {
return (tsig_key_info_);
}
private:
/// @brief The domain name of the domain.
std::string name_;
/// @brief The name of the TSIG key for use with this domain.
std<