mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 05:27:55 +00:00
[4088] Finished merge of trac4091 from master
This commit is contained in:
commit
11bc4b3cfc
5
AUTHORS
5
AUTHORS
@ -76,12 +76,15 @@ We have received the following contributions:
|
||||
- David Gutierrez Rueda, CERN
|
||||
2014-12: Support for client link-address option in DHCPv6 (RFC6939)
|
||||
|
||||
- Adam Kalmus, Gdank University of Technology
|
||||
- Adam Kalmus, Gdansk University of Technology
|
||||
2014-12: Extract MAC address from DUID-LL and DUID-LLT types
|
||||
2015-01: Extract MAC address from remote-id
|
||||
2015-05: MySQL schema extended to cover host reservation
|
||||
2015-10: Common MySQL Connector Pool
|
||||
|
||||
- Jinmei Tatuya
|
||||
2015-10: Pkt4o6 class improvements
|
||||
|
||||
Kea uses log4cplus (http://sourceforge.net/projects/log4cplus/) for logging,
|
||||
Boost (http://www.boost.org/) library for almost everything, and can use Botan
|
||||
(http://botan.randombit.net/) or OpenSSL (https://www.openssl.org/) for
|
||||
|
@ -1,3 +1,12 @@
|
||||
1043. [func] fdupont
|
||||
Implemented support for hex strings in client classification.
|
||||
(Trac #4091, git 406153af95404adb96296df09ec6033b484586e3)
|
||||
|
||||
1042. [doc] fdupont
|
||||
User Guide: parameters having default values may be omitted in the
|
||||
option definitions.
|
||||
(Trac #3927, git c7460e849258ec77cf1215a2baf840d98f1ab77b)
|
||||
|
||||
1041. [func] tomek
|
||||
A new library, libkea-eval has been edded. It is not functional
|
||||
yet, but its purpose is to provide a generic expression
|
||||
|
@ -1160,14 +1160,14 @@ It is merely echoed by the server
|
||||
should be left blank. Note that the above set of comments define the
|
||||
format of the new option and do not set its values.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
In the current release the default values are not propagated to the
|
||||
parser when the new configuration is being set. Therefore, all
|
||||
parameters must be specified at all times, even if their values are
|
||||
left blank.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>The <command>name</command>, <command>code</command> and
|
||||
<command>type</command> parameters are required, all others are
|
||||
optional. The <command>array</command> default value is
|
||||
<command>false</command>. The <command>record-types</command>
|
||||
and <command>encapsulate</command> default values are blank
|
||||
(i.e. ""). The default <command>space</command> is "dhcp4".
|
||||
</para>
|
||||
|
||||
<para>Once the new option format is defined, its value is set
|
||||
in the same way as for a standard option. For example the following
|
||||
|
@ -961,6 +961,8 @@ temporarily override a list of interface names and listen on all interfaces.
|
||||
<row><entry>erp-local-domain-name</entry><entry>65</entry><entry>fqdn</entry><entry>false</entry></row>
|
||||
<row><entry>rsoo</entry><entry>66</entry><entry>empty</entry><entry>false</entry></row>
|
||||
<row><entry>client-linklayer-addr</entry><entry>79</entry><entry>binary</entry><entry>false</entry></row>
|
||||
<!-- <row><entry>dhcpv4-message</entry><entry>87</entry><entry>binary</entry><entry>false</entry></row> -->
|
||||
<row><entry>dhcp4o6-server-addr</entry><entry>88</entry><entry>ipv6-address</entry><entry>true</entry></row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
@ -1022,6 +1024,15 @@ temporarily override a list of interface names and listen on all interfaces.
|
||||
set of comments define the format of the new option and do not set its
|
||||
values.
|
||||
</para>
|
||||
|
||||
<para>The <command>name</command>, <command>code</command> and
|
||||
<command>type</command> parameters are required, all others are
|
||||
optional. The <command>array</command> default value is
|
||||
<command>false</command>. The <command>record-types</command>
|
||||
and <command>encapsulate</command> default values are blank
|
||||
(i.e. ""). The default <command>space</command> is "dhcp6".
|
||||
</para>
|
||||
|
||||
<para>Once the new option format is defined, its value is set
|
||||
in the same way as for a standard option. For example the following
|
||||
commands set a global value that applies to all subnets.
|
||||
@ -1059,7 +1070,7 @@ temporarily override a list of interface names and listen on all interfaces.
|
||||
"space": "dhcp6",
|
||||
"type": "record",
|
||||
"array": false,
|
||||
"record-types": "ipv4-address, uint16, boolean, string",
|
||||
"record-types": "ipv6-address, uint16, boolean, string",
|
||||
"encapsulate": ""</userinput>
|
||||
}, ...
|
||||
],
|
||||
|
@ -219,6 +219,11 @@
|
||||
<simpara><command>kea-dhcp4.dhcpsrv</command> - this is a base
|
||||
logger for the libdhcpsrv library.</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><command>kea-dhcp4.eval</command> - this logger is used
|
||||
to log messages relating to the client classification expression
|
||||
evaluation code.</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><command>kea-dhcp4.hooks</command> - this logger is used
|
||||
to log messages related to management of hooks libraries, e.g.
|
||||
@ -302,6 +307,11 @@
|
||||
<simpara><command>kea-dhcp6.dhcpsrv</command> - this is a base
|
||||
logger for the libdhcpsrv library.</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><command>kea-dhcp6.eval</command> - this logger is used
|
||||
to log messages relating to the client classification expression
|
||||
evaluation code.</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><command>kea-dhcp6.hooks</command> - this logger is used
|
||||
to log messages related to management of hooks libraries, e.g.
|
||||
|
@ -200,6 +200,12 @@ protected:
|
||||
parser = new OptionDataListParser(config_id, options_, AF_INET);
|
||||
} else if (config_id.compare("match-client-id") == 0) {
|
||||
parser = new BooleanParser(config_id, boolean_values_);
|
||||
} else if (config_id.compare("4o6-subnet") == 0) {
|
||||
parser = new StringParser(config_id, string_values_);
|
||||
} else if (config_id.compare("4o6-interface") == 0) {
|
||||
parser = new StringParser(config_id, string_values_);
|
||||
} else if (config_id.compare("4o6-interface-id") == 0) {
|
||||
parser = new StringParser(config_id, string_values_);
|
||||
} else {
|
||||
isc_throw(NotImplemented, "unsupported parameter: " << config_id);
|
||||
}
|
||||
@ -305,6 +311,43 @@ protected:
|
||||
<< ")");
|
||||
}
|
||||
|
||||
// Try 4o6 specific parameter: 4o6-interface
|
||||
string iface4o6 = string_values_->getOptionalParam("4o6-interface", "");
|
||||
if (!iface4o6.empty()) {
|
||||
subnet4->get4o6().setIface4o6(iface4o6);
|
||||
subnet4->get4o6().enabled(true);
|
||||
}
|
||||
|
||||
// Try 4o6 specific parameter: 4o6-subnet
|
||||
string subnet4o6 = string_values_->getOptionalParam("4o6-subnet", "");
|
||||
if (!subnet4o6.empty()) {
|
||||
size_t slash = subnet4o6.find("/");
|
||||
if (slash == std::string::npos) {
|
||||
isc_throw(DhcpConfigError, "Missing / in the 4o6-subnet parameter:"
|
||||
+ subnet4o6 +", expected format: prefix6/length");
|
||||
}
|
||||
string prefix = subnet4o6.substr(0, slash);
|
||||
string lenstr = subnet4o6.substr(slash + 1);
|
||||
|
||||
uint8_t len = 128;
|
||||
try {
|
||||
len = boost::lexical_cast<unsigned int>(lenstr.c_str());
|
||||
} catch (const boost::bad_lexical_cast &) {
|
||||
isc_throw(DhcpConfigError, "Invalid prefix length specified in "
|
||||
"4o6-subnet parameter: " + subnet4o6 + ", expected 0..128 value");
|
||||
}
|
||||
subnet4->get4o6().setSubnet4o6(IOAddress(prefix), len);
|
||||
subnet4->get4o6().enabled(true);
|
||||
}
|
||||
|
||||
// Try 4o6 specific paramter: 4o6-interface-id
|
||||
std::string ifaceid = string_values_->getOptionalParam("4o6-interface-id", "");
|
||||
if (!ifaceid.empty()) {
|
||||
OptionBuffer tmp(ifaceid.begin(), ifaceid.end());
|
||||
OptionPtr opt(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
|
||||
subnet4->get4o6().setInterfaceId(opt);
|
||||
subnet4->get4o6().enabled(true);
|
||||
}
|
||||
|
||||
// Try setting up client class (if specified)
|
||||
try {
|
||||
@ -373,8 +416,8 @@ namespace dhcp {
|
||||
/// @return parser for specified global DHCPv4 parameter
|
||||
/// @throw NotImplemented if trying to create a parser for unknown
|
||||
/// config element
|
||||
DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id,
|
||||
ConstElementPtr element) {
|
||||
DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id,
|
||||
ConstElementPtr element) {
|
||||
DhcpConfigParser* parser = NULL;
|
||||
if ((config_id.compare("valid-lifetime") == 0) ||
|
||||
(config_id.compare("renew-timer") == 0) ||
|
||||
|
@ -1330,10 +1330,7 @@ TEST_F(Dhcp4ParserTest, optionDefIpv4Address) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1372,10 +1369,8 @@ TEST_F(Dhcp4ParserTest, optionDefRecord) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"record\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"uint16, ipv4-address, ipv6-address, string\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1422,19 +1417,13 @@ TEST_F(Dhcp4ParserTest, optionDefMultiple) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo-2\","
|
||||
" \"code\": 101,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1488,19 +1477,13 @@ TEST_F(Dhcp4ParserTest, optionDefDuplicate) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo-2\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1529,9 +1512,7 @@ TEST_F(Dhcp4ParserTest, optionDefArray) {
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": True,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1571,8 +1552,6 @@ TEST_F(Dhcp4ParserTest, optionDefEncapsulate) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"sub-opts-space\""
|
||||
" } ]"
|
||||
@ -1613,10 +1592,7 @@ TEST_F(Dhcp4ParserTest, optionDefInvalidName) {
|
||||
" \"name\": \"invalid%name\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"string\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1640,10 +1616,7 @@ TEST_F(Dhcp4ParserTest, optionDefInvalidType) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"sting\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1667,10 +1640,8 @@ TEST_F(Dhcp4ParserTest, optionDefInvalidRecordType) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"record\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"uint32,uint8,sting\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1694,8 +1665,6 @@ TEST_F(Dhcp4ParserTest, optionDefInvalidEncapsulatedSpace) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"invalid%space%name\""
|
||||
" } ]"
|
||||
@ -1724,7 +1693,6 @@ TEST_F(Dhcp4ParserTest, optionDefEncapsulatedSpaceAndArray) {
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": True,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"valid-space-name\""
|
||||
" } ]"
|
||||
@ -1750,8 +1718,6 @@ TEST_F(Dhcp4ParserTest, optionDefEncapsulateOwnSpace) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"isc\""
|
||||
" } ]"
|
||||
@ -1781,10 +1747,7 @@ TEST_F(Dhcp4ParserTest, optionStandardDefOverride) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 109,"
|
||||
" \"type\": \"string\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"dhcp4\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"dhcp4\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1818,10 +1781,7 @@ TEST_F(Dhcp4ParserTest, optionStandardDefOverride) {
|
||||
" \"name\": \"routers\","
|
||||
" \"code\": 3,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"dhcp4\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"dhcp4\""
|
||||
" } ]"
|
||||
"}";
|
||||
json = Element::fromJSON(config);
|
||||
@ -1843,10 +1803,7 @@ TEST_F(Dhcp4ParserTest, optionStandardDefOverride) {
|
||||
" \"name\": \"nis-server-addr\","
|
||||
" \"code\": 65,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"dhcp4\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"dhcp4\""
|
||||
" } ]"
|
||||
"}";
|
||||
json = Element::fromJSON(config);
|
||||
@ -1879,15 +1836,11 @@ TEST_F(Dhcp4ParserTest, optionDataDefaults) {
|
||||
"\"renew-timer\": 1000,"
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"dhcp-message\","
|
||||
" \"space\": \"dhcp4\","
|
||||
" \"code\": 56,"
|
||||
" \"data\": \"ABCDEF0105\","
|
||||
" \"csv-format\": False"
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"default-ip-ttl\","
|
||||
" \"space\": \"dhcp4\","
|
||||
" \"code\": 23,"
|
||||
" \"data\": \"01\","
|
||||
" \"csv-format\": False"
|
||||
" } ],"
|
||||
@ -1952,26 +1905,19 @@ TEST_F(Dhcp4ParserTest, optionDataTwoSpaces) {
|
||||
"\"renew-timer\": 1000,"
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"dhcp-message\","
|
||||
" \"space\": \"dhcp4\","
|
||||
" \"code\": 56,"
|
||||
" \"data\": \"ABCDEF0105\","
|
||||
" \"csv-format\": False"
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo\","
|
||||
" \"space\": \"isc\","
|
||||
" \"code\": 56,"
|
||||
" \"data\": \"1234\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"1234\""
|
||||
" } ],"
|
||||
"\"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 56,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ],"
|
||||
"\"subnet4\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
|
||||
@ -2033,34 +1979,24 @@ TEST_F(Dhcp4ParserTest, optionDataEncapsulate) {
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"space\": \"isc\","
|
||||
" \"code\": 1,"
|
||||
" \"data\": \"1234\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"1234\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"space\": \"isc\","
|
||||
" \"code\": 2,"
|
||||
" \"data\": \"192.168.2.1\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"192.168.2.1\""
|
||||
" } ],"
|
||||
"\"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 1,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"code\": 2,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
|
||||
@ -2084,31 +2020,22 @@ TEST_F(Dhcp4ParserTest, optionDataEncapsulate) {
|
||||
"\"renew-timer\": 1000,"
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"base-option\","
|
||||
" \"space\": \"dhcp4\","
|
||||
" \"code\": 222,"
|
||||
" \"data\": \"11\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"11\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo\","
|
||||
" \"space\": \"isc\","
|
||||
" \"code\": 1,"
|
||||
" \"data\": \"1234\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"1234\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"space\": \"isc\","
|
||||
" \"code\": 2,"
|
||||
" \"data\": \"192.168.2.1\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"192.168.2.1\""
|
||||
" } ],"
|
||||
"\"option-def\": [ {"
|
||||
" \"name\": \"base-option\","
|
||||
" \"code\": 222,"
|
||||
" \"type\": \"uint8\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"dhcp4\","
|
||||
" \"encapsulate\": \"isc\""
|
||||
"},"
|
||||
@ -2116,19 +2043,13 @@ TEST_F(Dhcp4ParserTest, optionDataEncapsulate) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 1,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"code\": 2,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ],"
|
||||
"\"subnet4\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
|
||||
@ -2180,8 +2101,6 @@ TEST_F(Dhcp4ParserTest, optionDataInSingleSubnet) {
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"dhcp-message\","
|
||||
" \"space\": \"dhcp4\","
|
||||
" \"code\": 56,"
|
||||
" \"data\": \"AB\","
|
||||
" \"csv-format\": False"
|
||||
" } ],"
|
||||
@ -2190,15 +2109,11 @@ TEST_F(Dhcp4ParserTest, optionDataInSingleSubnet) {
|
||||
" \"subnet\": \"192.0.2.0/24\", "
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"dhcp-message\","
|
||||
" \"space\": \"dhcp4\","
|
||||
" \"code\": 56,"
|
||||
" \"data\": \"ABCDEF0105\","
|
||||
" \"csv-format\": False"
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"default-ip-ttl\","
|
||||
" \"space\": \"dhcp4\","
|
||||
" \"code\": 23,"
|
||||
" \"data\": \"01\","
|
||||
" \"csv-format\": False"
|
||||
" } ]"
|
||||
@ -2337,8 +2252,6 @@ TEST_F(Dhcp4ParserTest, optionDataInMultipleSubnets) {
|
||||
" \"subnet\": \"192.0.2.0/24\", "
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"dhcp-message\","
|
||||
" \"space\": \"dhcp4\","
|
||||
" \"code\": 56,"
|
||||
" \"data\": \"0102030405060708090A\","
|
||||
" \"csv-format\": False"
|
||||
" } ]"
|
||||
@ -2348,8 +2261,6 @@ TEST_F(Dhcp4ParserTest, optionDataInMultipleSubnets) {
|
||||
" \"subnet\": \"192.0.3.0/24\", "
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"default-ip-ttl\","
|
||||
" \"space\": \"dhcp4\","
|
||||
" \"code\": 23,"
|
||||
" \"data\": \"FF\","
|
||||
" \"csv-format\": False"
|
||||
" } ]"
|
||||
@ -2610,34 +2521,24 @@ TEST_F(Dhcp4ParserTest, stdOptionDataEncapsulate) {
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"space\": \"vendor-encapsulated-options-space\","
|
||||
" \"code\": 1,"
|
||||
" \"data\": \"1234\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"1234\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"space\": \"vendor-encapsulated-options-space\","
|
||||
" \"code\": 2,"
|
||||
" \"data\": \"192.168.2.1\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"192.168.2.1\""
|
||||
" } ],"
|
||||
"\"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 1,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"vendor-encapsulated-options-space\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"vendor-encapsulated-options-space\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"code\": 2,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"vendor-encapsulated-options-space\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"vendor-encapsulated-options-space\""
|
||||
" } ]"
|
||||
"}";
|
||||
|
||||
@ -2665,17 +2566,12 @@ TEST_F(Dhcp4ParserTest, stdOptionDataEncapsulate) {
|
||||
"\"renew-timer\": 1000,"
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"vendor-encapsulated-options\","
|
||||
" \"space\": \"dhcp4\","
|
||||
" \"code\": 43,"
|
||||
" \"data\": \"\","
|
||||
" \"csv-format\": False"
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo\","
|
||||
" \"space\": \"vendor-encapsulated-options-space\","
|
||||
" \"code\": 1,"
|
||||
" \"data\": \"1234\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"1234\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
@ -2688,19 +2584,13 @@ TEST_F(Dhcp4ParserTest, stdOptionDataEncapsulate) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 1,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"vendor-encapsulated-options-space\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"vendor-encapsulated-options-space\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"code\": 2,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"vendor-encapsulated-options-space\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"vendor-encapsulated-options-space\""
|
||||
" } ],"
|
||||
"\"subnet4\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
|
||||
@ -2834,17 +2724,13 @@ TEST_F(Dhcp4ParserTest, vendorOptionsCsv) {
|
||||
" \"name\": \"foo\","
|
||||
" \"space\": \"vendor-4491\","
|
||||
" \"code\": 100,"
|
||||
" \"data\": \"this is a string vendor-opt\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"this is a string vendor-opt\""
|
||||
" } ],"
|
||||
"\"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"string\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"vendor-4491\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"vendor-4491\""
|
||||
" } ],"
|
||||
"\"subnet4\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
|
||||
@ -2911,26 +2797,19 @@ buildHooksLibrariesConfig(const std::vector<std::string>& libraries) {
|
||||
"\"renew-timer\": 1000,"
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"dhcp-message\","
|
||||
" \"space\": \"dhcp4\","
|
||||
" \"code\": 56,"
|
||||
" \"data\": \"ABCDEF0105\","
|
||||
" \"csv-format\": False"
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo\","
|
||||
" \"space\": \"isc\","
|
||||
" \"code\": 56,"
|
||||
" \"data\": \"1234\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"1234\""
|
||||
" } ],"
|
||||
"\"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 56,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ],"
|
||||
"\"subnet4\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
|
||||
@ -3782,4 +3661,241 @@ TEST_F(Dhcp4ParserTest, expiredLeasesProcessingError) {
|
||||
EXPECT_TRUE(errorContainsPosition(status, "<string>"));
|
||||
}
|
||||
|
||||
|
||||
// Checks if the DHCPv4 is able to parse the configuration without 4o6 parameters
|
||||
// and does not set 4o6 fields at all.
|
||||
TEST_F(Dhcp4ParserTest, 4o6default) {
|
||||
|
||||
ConstElementPtr status;
|
||||
|
||||
// Just a plain v4 config (no 4o6 parameters)
|
||||
string config = "{ " + genIfaceConfig() + "," +
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"subnet4\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
|
||||
" \"subnet\": \"192.0.2.0/24\" } ],"
|
||||
"\"valid-lifetime\": 4000 }";
|
||||
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
|
||||
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
|
||||
|
||||
// check if returned status is OK
|
||||
checkResult(status, 0);
|
||||
|
||||
// Now check if the configuration was indeed handled and we have
|
||||
// expected pool configured.
|
||||
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
|
||||
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
|
||||
ASSERT_TRUE(subnet);
|
||||
|
||||
Cfg4o6& dhcp4o6 = subnet->get4o6();
|
||||
EXPECT_FALSE(dhcp4o6.enabled());
|
||||
}
|
||||
|
||||
// Checks if the DHCPv4 is able to parse the configuration with 4o6 subnet
|
||||
// defined.
|
||||
TEST_F(Dhcp4ParserTest, 4o6subnet) {
|
||||
|
||||
ConstElementPtr status;
|
||||
|
||||
// Just a plain v4 config (no 4o6 parameters)
|
||||
string config = "{ " + genIfaceConfig() + "," +
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"subnet4\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
|
||||
" \"subnet\": \"192.0.2.0/24\","
|
||||
" \"4o6-subnet\": \"2001:db8::123/45\" } ],"
|
||||
"\"valid-lifetime\": 4000 }";
|
||||
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
|
||||
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
|
||||
|
||||
// check if returned status is OK
|
||||
checkResult(status, 0);
|
||||
|
||||
// Now check if the configuration was indeed handled and we have
|
||||
// expected pool configured.
|
||||
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
|
||||
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
|
||||
ASSERT_TRUE(subnet);
|
||||
|
||||
Cfg4o6& dhcp4o6 = subnet->get4o6();
|
||||
EXPECT_TRUE(dhcp4o6.enabled());
|
||||
EXPECT_EQ(IOAddress("2001:db8::123"), dhcp4o6.getSubnet4o6().first);
|
||||
EXPECT_EQ(45, dhcp4o6.getSubnet4o6().second);
|
||||
}
|
||||
|
||||
// Checks if the DHCPv4 is able to parse the configuration with 4o6 subnet
|
||||
// defined.
|
||||
TEST_F(Dhcp4ParserTest, 4o6subnetBogus) {
|
||||
|
||||
ConstElementPtr status;
|
||||
|
||||
// Just a plain v4 config (no 4o6 parameters)
|
||||
string config[] = {
|
||||
// Bogus configuration 1: missing / in subnet
|
||||
"{ " + genIfaceConfig() + "," +
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"subnet4\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
|
||||
" \"subnet\": \"192.0.2.0/24\","
|
||||
" \"4o6-subnet\": \"2001:db8::123\" } ],"
|
||||
"\"valid-lifetime\": 4000 }",
|
||||
|
||||
// Bogus configuration 2: incorrect address
|
||||
"{ " + genIfaceConfig() + "," +
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"subnet4\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
|
||||
" \"subnet\": \"192.0.2.0/24\","
|
||||
" \"4o6-subnet\": \"2001:db8:bogus/45\" } ],"
|
||||
"\"valid-lifetime\": 4000 }",
|
||||
|
||||
// Bogus configuration 3: incorrect prefix lenght
|
||||
"{ " + genIfaceConfig() + "," +
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"subnet4\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
|
||||
" \"subnet\": \"192.0.2.0/24\","
|
||||
" \"4o6-subnet\": \"2001:db8::123/200\" } ],"
|
||||
"\"valid-lifetime\": 4000 }"
|
||||
};
|
||||
|
||||
ElementPtr json1 = Element::fromJSON(config[0]);
|
||||
ElementPtr json2 = Element::fromJSON(config[0]);
|
||||
ElementPtr json3 = Element::fromJSON(config[0]);
|
||||
|
||||
// Check that the first config is rejected.
|
||||
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json1));
|
||||
checkResult(status, 1);
|
||||
|
||||
// Check that the second config is rejected.
|
||||
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json2));
|
||||
checkResult(status, 1);
|
||||
|
||||
// Check that the third config is rejected.
|
||||
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json3));
|
||||
checkResult(status, 1);
|
||||
}
|
||||
|
||||
|
||||
// Checks if the DHCPv4 is able to parse the configuration with 4o6 network
|
||||
// interface defined.
|
||||
TEST_F(Dhcp4ParserTest, 4o6iface) {
|
||||
|
||||
ConstElementPtr status;
|
||||
|
||||
// Just a plain v4 config (no 4o6 parameters)
|
||||
string config = "{ " + genIfaceConfig() + "," +
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"subnet4\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
|
||||
" \"subnet\": \"192.0.2.0/24\","
|
||||
" \"4o6-interface\": \"ethX\" } ],"
|
||||
"\"valid-lifetime\": 4000 }";
|
||||
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
|
||||
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
|
||||
|
||||
// check if returned status is OK
|
||||
checkResult(status, 0);
|
||||
|
||||
// Now check if the configuration was indeed handled and we have
|
||||
// expected pool configured.
|
||||
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
|
||||
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
|
||||
ASSERT_TRUE(subnet);
|
||||
|
||||
Cfg4o6& dhcp4o6 = subnet->get4o6();
|
||||
EXPECT_TRUE(dhcp4o6.enabled());
|
||||
EXPECT_EQ("ethX", dhcp4o6.getIface4o6());
|
||||
}
|
||||
|
||||
// Checks if the DHCPv4 is able to parse the configuration with both 4o6 network
|
||||
// interface and v6 subnet defined.
|
||||
TEST_F(Dhcp4ParserTest, 4o6subnetIface) {
|
||||
|
||||
ConstElementPtr status;
|
||||
|
||||
// Just a plain v4 config (no 4o6 parameters)
|
||||
string config = "{ " + genIfaceConfig() + "," +
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"subnet4\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
|
||||
" \"subnet\": \"192.0.2.0/24\","
|
||||
" \"4o6-subnet\": \"2001:db8::543/21\","
|
||||
" \"4o6-interface\": \"ethX\" } ],"
|
||||
"\"valid-lifetime\": 4000 }";
|
||||
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
|
||||
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
|
||||
|
||||
// check if returned status is OK
|
||||
checkResult(status, 0);
|
||||
|
||||
// Now check if the configuration was indeed handled and we have
|
||||
// expected subnet configured...
|
||||
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
|
||||
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
|
||||
ASSERT_TRUE(subnet);
|
||||
|
||||
// ... and that subnet has 4o6 network interface specified.
|
||||
Cfg4o6& dhcp4o6 = subnet->get4o6();
|
||||
EXPECT_TRUE(dhcp4o6.enabled());
|
||||
EXPECT_EQ(IOAddress("2001:db8::543"), dhcp4o6.getSubnet4o6().first);
|
||||
EXPECT_EQ(21, dhcp4o6.getSubnet4o6().second);
|
||||
EXPECT_EQ("ethX", dhcp4o6.getIface4o6());
|
||||
}
|
||||
|
||||
// Checks if the DHCPv4 is able to parse the configuration with 4o6 network
|
||||
// interface-id.
|
||||
TEST_F(Dhcp4ParserTest, 4o6subnetInterfaceId) {
|
||||
|
||||
ConstElementPtr status;
|
||||
|
||||
// Just a plain v4 config (no 4o6 parameters)
|
||||
string config = "{ " + genIfaceConfig() + "," +
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"subnet4\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
|
||||
" \"subnet\": \"192.0.2.0/24\","
|
||||
" \"4o6-interface-id\": \"vlan123\" } ],"
|
||||
"\"valid-lifetime\": 4000 }";
|
||||
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
|
||||
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
|
||||
|
||||
// check if returned status is OK
|
||||
checkResult(status, 0);
|
||||
|
||||
// Now check if the configuration was indeed handled and we have
|
||||
// expected 4o6-interface-id configured.
|
||||
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
|
||||
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
|
||||
ASSERT_TRUE(subnet);
|
||||
|
||||
Cfg4o6& dhcp4o6 = subnet->get4o6();
|
||||
EXPECT_TRUE(dhcp4o6.enabled());
|
||||
OptionPtr ifaceid = dhcp4o6.getInterfaceId();
|
||||
ASSERT_TRUE(ifaceid);
|
||||
|
||||
vector<uint8_t> data = ifaceid->getData();
|
||||
EXPECT_EQ(7, data.size());
|
||||
const char *exp = "vlan123";
|
||||
EXPECT_EQ(0, memcmp(&data[0], exp, data.size()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -361,7 +361,7 @@ TEST_F(CtrlChannelDhcpv4SrvTest, controlLeasesReclaim) {
|
||||
time(NULL) - 100, SubnetID(1)));
|
||||
|
||||
// Add leases to the database.
|
||||
LeaseMgr& lease_mgr = LeaseMgrFactory().instance();
|
||||
LeaseMgr& lease_mgr = LeaseMgrFactory::instance();
|
||||
ASSERT_NO_THROW(lease_mgr.addLease(lease0));
|
||||
ASSERT_NO_THROW(lease_mgr.addLease(lease1));
|
||||
|
||||
@ -419,7 +419,7 @@ TEST_F(CtrlChannelDhcpv4SrvTest, controlLeasesReclaimRemove) {
|
||||
time(NULL) - 100, SubnetID(1)));
|
||||
|
||||
// Add leases to the database.
|
||||
LeaseMgr& lease_mgr = LeaseMgrFactory().instance();
|
||||
LeaseMgr& lease_mgr = LeaseMgrFactory::instance();
|
||||
ASSERT_NO_THROW(lease_mgr.addLease(lease0));
|
||||
ASSERT_NO_THROW(lease_mgr.addLease(lease1));
|
||||
|
||||
|
@ -53,10 +53,7 @@ const char* DECLINE_CONFIGS[] = {
|
||||
" \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"routers\","
|
||||
" \"code\": 3,"
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\""
|
||||
" } ]"
|
||||
" } ]"
|
||||
"}"
|
||||
|
@ -77,31 +77,19 @@ const char* DORA_CONFIGS[] = {
|
||||
" \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"routers\","
|
||||
" \"code\": 3,"
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"domain-name-servers\","
|
||||
" \"code\": 6,"
|
||||
" \"data\": \"10.0.0.202,10.0.0.203\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.202,10.0.0.203\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"log-servers\","
|
||||
" \"code\": 7,"
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"cookie-servers\","
|
||||
" \"code\": 8,"
|
||||
" \"data\": \"10.0.0.202,10.0.0.203\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.202,10.0.0.203\""
|
||||
" } ]"
|
||||
" } ]"
|
||||
"}",
|
||||
@ -116,31 +104,19 @@ const char* DORA_CONFIGS[] = {
|
||||
" \"subnet\": \"192.0.2.0/24\", "
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"routers\","
|
||||
" \"code\": 3,"
|
||||
" \"data\": \"192.0.2.200,192.0.2.201\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"192.0.2.200,192.0.2.201\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"domain-name-servers\","
|
||||
" \"code\": 6,"
|
||||
" \"data\": \"192.0.2.202,192.0.2.203\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"192.0.2.202,192.0.2.203\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"log-servers\","
|
||||
" \"code\": 7,"
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"cookie-servers\","
|
||||
" \"code\": 8,"
|
||||
" \"data\": \"10.0.0.202,10.0.0.203\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.202,10.0.0.203\""
|
||||
" } ]"
|
||||
" } ]"
|
||||
"}",
|
||||
@ -174,10 +150,7 @@ const char* DORA_CONFIGS[] = {
|
||||
" \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"routers\","
|
||||
" \"code\": 3,"
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\""
|
||||
" } ]"
|
||||
" } ]"
|
||||
"}",
|
||||
|
@ -47,10 +47,7 @@ const char* CONFIGS[] = {
|
||||
" \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"routers\","
|
||||
" \"code\": 3,"
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\""
|
||||
" } ],"
|
||||
" \"reservations\": ["
|
||||
" {"
|
||||
@ -74,10 +71,7 @@ const char* CONFIGS[] = {
|
||||
" \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"routers\","
|
||||
" \"code\": 3,"
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\""
|
||||
" } ],"
|
||||
" \"reservations\": ["
|
||||
" {"
|
||||
|
@ -58,31 +58,19 @@ const char* INFORM_CONFIGS[] = {
|
||||
" \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"routers\","
|
||||
" \"code\": 3,"
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"domain-name-servers\","
|
||||
" \"code\": 6,"
|
||||
" \"data\": \"10.0.0.202,10.0.0.203\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.202,10.0.0.203\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"log-servers\","
|
||||
" \"code\": 7,"
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"cookie-servers\","
|
||||
" \"code\": 8,"
|
||||
" \"data\": \"10.0.0.202,10.0.0.203\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.202,10.0.0.203\""
|
||||
" } ]"
|
||||
" } ]"
|
||||
"}",
|
||||
@ -96,31 +84,19 @@ const char* INFORM_CONFIGS[] = {
|
||||
" \"subnet\": \"192.0.2.0/24\", "
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"routers\","
|
||||
" \"code\": 3,"
|
||||
" \"data\": \"192.0.2.200,192.0.2.201\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"192.0.2.200,192.0.2.201\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"domain-name-servers\","
|
||||
" \"code\": 6,"
|
||||
" \"data\": \"192.0.2.202,192.0.2.203\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"192.0.2.202,192.0.2.203\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"log-servers\","
|
||||
" \"code\": 7,"
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"cookie-servers\","
|
||||
" \"code\": 8,"
|
||||
" \"data\": \"10.0.0.202,10.0.0.203\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.202,10.0.0.203\""
|
||||
" } ]"
|
||||
" } ]"
|
||||
"}"
|
||||
|
@ -377,7 +377,7 @@ TEST_F(JSONFileBackendTest, timers) {
|
||||
lease_reclaimed->state_ = Lease4::STATE_EXPIRED_RECLAIMED;
|
||||
|
||||
// Add leases to the database.
|
||||
LeaseMgr& lease_mgr = LeaseMgrFactory().instance();
|
||||
LeaseMgr& lease_mgr = LeaseMgrFactory::instance();
|
||||
ASSERT_NO_THROW(lease_mgr.addLease(lease_expired));
|
||||
ASSERT_NO_THROW(lease_mgr.addLease(lease_reclaimed));
|
||||
|
||||
|
@ -53,10 +53,7 @@ const char* RELEASE_CONFIGS[] = {
|
||||
" \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"routers\","
|
||||
" \"code\": 3,"
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\","
|
||||
" \"csv-format\": true,"
|
||||
" \"space\": \"dhcp4\""
|
||||
" \"data\": \"10.0.0.200,10.0.0.201\""
|
||||
" } ]"
|
||||
" } ]"
|
||||
"}"
|
||||
|
@ -665,8 +665,8 @@ namespace dhcp {
|
||||
/// @return parser for specified global DHCPv6 parameter
|
||||
/// @throw NotImplemented if trying to create a parser for unknown config
|
||||
/// element
|
||||
DhcpConfigParser* createGlobal6DhcpConfigParser(const std::string& config_id,
|
||||
ConstElementPtr element) {
|
||||
DhcpConfigParser* createGlobal6DhcpConfigParser(const std::string& config_id,
|
||||
ConstElementPtr element) {
|
||||
DhcpConfigParser* parser = NULL;
|
||||
if ((config_id.compare("preferred-lifetime") == 0) ||
|
||||
(config_id.compare("valid-lifetime") == 0) ||
|
||||
|
@ -205,10 +205,7 @@ public:
|
||||
" \"name\": \"bool-option\","
|
||||
" \"code\": 1000,"
|
||||
" \"type\": \"boolean\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"dhcp6\""
|
||||
"} ],"
|
||||
"\"subnet6\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ],"
|
||||
@ -1572,10 +1569,7 @@ TEST_F(Dhcp6ParserTest, optionDefIpv6Address) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"ipv6-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1612,10 +1606,8 @@ TEST_F(Dhcp6ParserTest, optionDefRecord) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"record\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"uint16, ipv4-address, ipv6-address, string\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1661,19 +1653,13 @@ TEST_F(Dhcp6ParserTest, optionDefMultiple) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo-2\","
|
||||
" \"code\": 101,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1725,19 +1711,13 @@ TEST_F(Dhcp6ParserTest, optionDefDuplicate) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo-2\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1766,9 +1746,7 @@ TEST_F(Dhcp6ParserTest, optionDefArray) {
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": True,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1806,8 +1784,6 @@ TEST_F(Dhcp6ParserTest, optionDefEncapsulate) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"sub-opts-space\""
|
||||
" } ]"
|
||||
@ -1847,10 +1823,7 @@ TEST_F(Dhcp6ParserTest, optionDefInvalidName) {
|
||||
" \"name\": \"invalid%name\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"string\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1874,10 +1847,7 @@ TEST_F(Dhcp6ParserTest, optionDefInvalidType) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"sting\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1901,10 +1871,8 @@ TEST_F(Dhcp6ParserTest, optionDefInvalidRecordType) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"record\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"uint32,uint8,sting\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -1928,8 +1896,6 @@ TEST_F(Dhcp6ParserTest, optionDefInvalidEncapsulatedSpace) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"invalid%space%name\""
|
||||
" } ]"
|
||||
@ -1958,7 +1924,6 @@ TEST_F(Dhcp6ParserTest, optionDefEncapsulatedSpaceAndArray) {
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": True,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"valid-space-name\""
|
||||
" } ]"
|
||||
@ -1984,8 +1949,6 @@ TEST_F(Dhcp6ParserTest, optionDefEncapsulateOwnSpace) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"isc\""
|
||||
" } ]"
|
||||
@ -2016,10 +1979,7 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"string\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"dhcp6\""
|
||||
" } ]"
|
||||
"}";
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
@ -2053,10 +2013,7 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 3,"
|
||||
" \"type\": \"string\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"dhcp6\""
|
||||
" } ]"
|
||||
"}";
|
||||
json = Element::fromJSON(config);
|
||||
@ -2078,10 +2035,7 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) {
|
||||
" \"name\": \"geolocation\","
|
||||
" \"code\": 63,"
|
||||
" \"type\": \"string\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"dhcp6\""
|
||||
" } ]"
|
||||
"}";
|
||||
json = Element::fromJSON(config);
|
||||
@ -2114,17 +2068,12 @@ TEST_F(Dhcp6ParserTest, optionDataDefaults) {
|
||||
"\"renew-timer\": 1000,"
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"subscriber-id\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"code\": 38,"
|
||||
" \"data\": \"ABCDEF0105\","
|
||||
" \"csv-format\": False"
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"preference\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"code\": 7,"
|
||||
" \"data\": \"01\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"01\""
|
||||
" } ],"
|
||||
"\"subnet6\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ],"
|
||||
@ -2196,26 +2145,19 @@ TEST_F(Dhcp6ParserTest, optionDataTwoSpaces) {
|
||||
"\"renew-timer\": 1000,"
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"subscriber-id\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"code\": 38,"
|
||||
" \"data\": \"ABCDEF0105\","
|
||||
" \"csv-format\": False"
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo\","
|
||||
" \"space\": \"isc\","
|
||||
" \"code\": 38,"
|
||||
" \"data\": \"1234\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"1234\""
|
||||
" } ],"
|
||||
"\"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 38,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ],"
|
||||
"\"subnet6\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ],"
|
||||
@ -2278,34 +2220,24 @@ TEST_F(Dhcp6ParserTest, optionDataEncapsulate) {
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"space\": \"isc\","
|
||||
" \"code\": 110,"
|
||||
" \"data\": \"1234\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"1234\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"space\": \"isc\","
|
||||
" \"code\": 111,"
|
||||
" \"data\": \"192.168.2.1\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"192.168.2.1\""
|
||||
" } ],"
|
||||
"\"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 110,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"code\": 111,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
|
||||
@ -2330,31 +2262,22 @@ TEST_F(Dhcp6ParserTest, optionDataEncapsulate) {
|
||||
"\"renew-timer\": 1000,"
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"base-option\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"code\": 100,"
|
||||
" \"data\": \"11\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"11\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo\","
|
||||
" \"space\": \"isc\","
|
||||
" \"code\": 110,"
|
||||
" \"data\": \"1234\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"1234\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"space\": \"isc\","
|
||||
" \"code\": 111,"
|
||||
" \"data\": \"192.168.2.1\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"192.168.2.1\""
|
||||
" } ],"
|
||||
"\"option-def\": [ {"
|
||||
" \"name\": \"base-option\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"uint8\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"encapsulate\": \"isc\""
|
||||
"},"
|
||||
@ -2362,19 +2285,13 @@ TEST_F(Dhcp6ParserTest, optionDataEncapsulate) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 110,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"code\": 111,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ],"
|
||||
"\"subnet6\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ],"
|
||||
@ -2429,8 +2346,6 @@ TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) {
|
||||
" \"subnet\": \"2001:db8:1::/64\", "
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"subscriber-id\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"code\": 38,"
|
||||
" \"data\": \"0102030405060708090A\","
|
||||
" \"csv-format\": False"
|
||||
" } ]"
|
||||
@ -2440,8 +2355,6 @@ TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) {
|
||||
" \"subnet\": \"2001:db8:2::/64\", "
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"user-class\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"code\": 15,"
|
||||
" \"data\": \"FFFEFDFCFB\","
|
||||
" \"csv-format\": False"
|
||||
" } ]"
|
||||
@ -2804,17 +2717,13 @@ TEST_F(Dhcp6ParserTest, vendorOptionsCsv) {
|
||||
" \"name\": \"foo\","
|
||||
" \"space\": \"vendor-4491\","
|
||||
" \"code\": 100,"
|
||||
" \"data\": \"this is a string vendor-opt\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"this is a string vendor-opt\""
|
||||
" } ],"
|
||||
"\"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"string\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"vendor-4491\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"vendor-4491\""
|
||||
" } ],"
|
||||
"\"subnet6\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ],"
|
||||
@ -2869,34 +2778,24 @@ TEST_F(Dhcp6ParserTest, DISABLED_stdOptionDataEncapsulate) {
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"space\": \"vendor-opts-space\","
|
||||
" \"code\": 110,"
|
||||
" \"data\": \"1234\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"1234\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"space\": \"vendor-opts-space\","
|
||||
" \"code\": 111,"
|
||||
" \"data\": \"192.168.2.1\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"192.168.2.1\""
|
||||
" } ],"
|
||||
"\"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 110,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"vendor-opts-space\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"vendor-opts-space\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"code\": 111,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"vendor-opts-space\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"vendor-opts-space\""
|
||||
" } ]"
|
||||
"}";
|
||||
|
||||
@ -2923,42 +2822,29 @@ TEST_F(Dhcp6ParserTest, DISABLED_stdOptionDataEncapsulate) {
|
||||
"\"renew-timer\": 1000,"
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"vendor-opts\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"code\": 17,"
|
||||
" \"data\": \"1234\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"1234\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo\","
|
||||
" \"space\": \"vendor-opts-space\","
|
||||
" \"code\": 110,"
|
||||
" \"data\": \"1234\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"1234\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"space\": \"vendor-opts-space\","
|
||||
" \"code\": 111,"
|
||||
" \"data\": \"192.168.2.1\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"192.168.2.1\""
|
||||
" } ],"
|
||||
"\"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 110,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"vendor-opts-space\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"vendor-opts-space\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"code\": 111,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"vendor-opts-space\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"vendor-opts-space\""
|
||||
" } ],"
|
||||
"\"subnet6\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ],"
|
||||
@ -3049,34 +2935,24 @@ buildHooksLibrariesConfig(const std::vector<std::string>& libraries) {
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"space\": \"vendor-opts-space\","
|
||||
" \"code\": 110,"
|
||||
" \"data\": \"1234\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"1234\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"space\": \"vendor-opts-space\","
|
||||
" \"code\": 111,"
|
||||
" \"data\": \"192.168.2.1\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"192.168.2.1\""
|
||||
" } ],"
|
||||
"\"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 110,"
|
||||
" \"type\": \"uint32\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"vendor-opts-space\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"vendor-opts-space\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"foo2\","
|
||||
" \"code\": 111,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"vendor-opts-space\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"vendor-opts-space\""
|
||||
" } ]"
|
||||
"}");
|
||||
|
||||
|
@ -436,7 +436,7 @@ TEST_F(CtrlChannelDhcpv6SrvTest, controlLeasesReclaim) {
|
||||
lease1->cltt_ = time(NULL) - 100;
|
||||
|
||||
// Add leases to the database.
|
||||
LeaseMgr& lease_mgr = LeaseMgrFactory().instance();
|
||||
LeaseMgr& lease_mgr = LeaseMgrFactory::instance();
|
||||
ASSERT_NO_THROW(lease_mgr.addLease(lease0));
|
||||
ASSERT_NO_THROW(lease_mgr.addLease(lease1));
|
||||
|
||||
@ -498,7 +498,7 @@ TEST_F(CtrlChannelDhcpv6SrvTest, controlLeasesReclaimRemove) {
|
||||
lease1->cltt_ = time(NULL) - 100;
|
||||
|
||||
// Add leases to the database.
|
||||
LeaseMgr& lease_mgr = LeaseMgrFactory().instance();
|
||||
LeaseMgr& lease_mgr = LeaseMgrFactory::instance();
|
||||
ASSERT_NO_THROW(lease_mgr.addLease(lease0));
|
||||
ASSERT_NO_THROW(lease_mgr.addLease(lease1));
|
||||
|
||||
|
@ -300,15 +300,10 @@ TEST_F(Dhcpv6SrvTest, advertiseOptions) {
|
||||
" \"interface\": \"eth0\", "
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"dns-servers\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"code\": 23,"
|
||||
" \"data\": \"2001:db8:1234:FFFF::1, 2001:db8:1234:FFFF::2\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"2001:db8:1234:FFFF::1, 2001:db8:1234:FFFF::2\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"subscriber-id\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"code\": 38,"
|
||||
" \"data\": \"1234\","
|
||||
" \"csv-format\": False"
|
||||
" } ]"
|
||||
@ -1615,17 +1610,12 @@ TEST_F(Dhcpv6SrvTest, vendorOptionsORO) {
|
||||
" \"name\": \"config-file\","
|
||||
" \"code\": 33,"
|
||||
" \"type\": \"string\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"vendor-4491\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"vendor-4491\""
|
||||
" } ],"
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"config-file\","
|
||||
" \"space\": \"vendor-4491\","
|
||||
" \"code\": 33,"
|
||||
" \"data\": \"normal_erouter_v6.cm\","
|
||||
" \"csv-format\": True"
|
||||
" \"data\": \"normal_erouter_v6.cm\""
|
||||
" }],"
|
||||
"\"subnet6\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
|
||||
@ -2305,11 +2295,7 @@ TEST_F(Dhcpv6SrvTest, rsooOverride) {
|
||||
" \"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 120,"
|
||||
" \"type\": \"binary\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"type\": \"binary\""
|
||||
" } ],"
|
||||
" \"option-data\": [ {"
|
||||
" \"code\": 120,"
|
||||
|
@ -321,7 +321,7 @@ TEST_F(JSONFileBackendTest, timers) {
|
||||
lease_reclaimed->state_ = Lease6::STATE_EXPIRED_RECLAIMED;
|
||||
|
||||
// Add leases to the database.
|
||||
LeaseMgr& lease_mgr = LeaseMgrFactory().instance();
|
||||
LeaseMgr& lease_mgr = LeaseMgrFactory::instance();
|
||||
ASSERT_NO_THROW(lease_mgr.addLease(lease_expired));
|
||||
ASSERT_NO_THROW(lease_mgr.addLease(lease_reclaimed));
|
||||
|
||||
|
@ -48,6 +48,7 @@ libkea_dhcp___la_SOURCES += protocol_util.cc protocol_util.h
|
||||
libkea_dhcp___la_SOURCES += pkt.cc pkt.h
|
||||
libkea_dhcp___la_SOURCES += pkt6.cc pkt6.h
|
||||
libkea_dhcp___la_SOURCES += pkt4.cc pkt4.h
|
||||
libkea_dhcp___la_SOURCES += pkt4o6.cc pkt4o6.h
|
||||
libkea_dhcp___la_SOURCES += pkt_filter.h pkt_filter.cc
|
||||
libkea_dhcp___la_SOURCES += pkt_filter6.h pkt_filter6.cc
|
||||
libkea_dhcp___la_SOURCES += pkt_filter_inet.cc pkt_filter_inet.h
|
||||
|
@ -110,8 +110,8 @@
|
||||
//#define D6O_ADDRSEL 84 /* RFC7078 */
|
||||
//#define D6O_ADDRSEL_TABLE 85 /* RFC7078 */
|
||||
//#define D6O_V6_PCP_SERVER 86 /* RFC7291 */
|
||||
//#define D6O_DHCPV4_MSG 87 /* RFC7341 */
|
||||
//#define D6O_DHCPV4_O_DHCPV6_SERVER 88 /* RFC7341 */
|
||||
#define D6O_DHCPV4_MSG 87 /* RFC7341 */
|
||||
#define D6O_DHCPV4_O_DHCPV6_SERVER 88 /* RFC7341 */
|
||||
//#define D6O_S46_RULE 89 /* RFC7598 */
|
||||
//#define D6O_S46_BR 90 /* RFC7598 */
|
||||
//#define D6O_S46_DMR 91 /* RFC7598 */
|
||||
@ -123,10 +123,9 @@
|
||||
//#define D6O_4RD 97 /* RFC7600 */
|
||||
//#define D6O_4RD_MAP_RULE 98 /* RFC7600 */
|
||||
//#define D6O_4RD_NON_MAP_RULE 99 /* RFC7600 */
|
||||
/* draft-ietf-dhc-dhcpv6-active-leasequery-04 */
|
||||
//#define D6O_LQ_BASE_TIME 100
|
||||
//#define D6O_LQ_START_TIME 101
|
||||
//#define D6O_LQ_END_TIME 102
|
||||
//#define D6O_LQ_BASE_TIME 100 /* RFC7653 */
|
||||
//#define D6O_LQ_START_TIME 101 /* RFC7653 */
|
||||
//#define D6O_LQ_END_TIME 102 /* RFC7653 */
|
||||
/* 103-142 unassigned */
|
||||
//#define D6O_IPV6_ADDRESS_ANDSF 143 /* RFC6153 */
|
||||
|
||||
@ -195,8 +194,8 @@
|
||||
//#define DHCPV6_RECONFIGURE_REQUEST 18
|
||||
//#define DHCPV6_RECONFIGURE_REPLY 19
|
||||
/* RFC 7341 */
|
||||
//#define DHCPV6_DHCPV4_QUERY 20
|
||||
//#define DHCPV6_DHCPV4_RESPONSE 21
|
||||
#define DHCPV6_DHCPV4_QUERY 20
|
||||
#define DHCPV6_DHCPV4_RESPONSE 21
|
||||
/* draft-ietf-dhc-dhcpv6-active-leasequery-04 */
|
||||
//#define DHCPV6_ACTIVELEASEQUERY 22
|
||||
//#define DHCPV6_STARTTLS 23
|
||||
@ -223,6 +222,11 @@ extern const int dhcpv6_type_name_max;
|
||||
// Taken from http://www.iana.org/assignments/enterprise-numbers
|
||||
#define ENTERPRISE_ID_ISC 2495
|
||||
|
||||
/* DHCPv4-over-DHCPv6 (RFC 7341) inter-process communication. These are option
|
||||
codes for the ISC vendor specific options used in 4o6 */
|
||||
#define ISC_V6_4O6_INTERFACE 60000
|
||||
#define ISC_V6_4O6_SRC_ADDRESS 60001
|
||||
|
||||
/* Offsets into IA_*'s where Option spaces commence. */
|
||||
#define IA_NA_OFFSET 12 /* IAID, T1, T2, all 4 octets each */
|
||||
#define IA_TA_OFFSET 4 /* IAID only, 4 octets */
|
||||
@ -298,4 +302,7 @@ extern const int dhcpv6_type_name_max;
|
||||
#define IRT_DEFAULT 86400
|
||||
#define IRT_MINIMUM 600
|
||||
|
||||
/* DHCPv4-query message flags (see RFC7341) */
|
||||
#define DHCPV4_QUERY_FLAGS_UNICAST (1 << 23)
|
||||
|
||||
#endif /* DHCP6_H */
|
||||
|
@ -110,6 +110,11 @@ LibDHCP::getVendorOption6Defs(const uint32_t vendor_id) {
|
||||
initVendorOptsDocsis6();
|
||||
}
|
||||
|
||||
if (vendor_id == ENTERPRISE_ID_ISC &&
|
||||
vendor6_defs_.find(ENTERPRISE_ID_ISC) == vendor6_defs_.end()) {
|
||||
initVendorOptsIsc6();
|
||||
}
|
||||
|
||||
VendorOptionDefContainers::const_iterator def = vendor6_defs_.find(vendor_id);
|
||||
if (def == vendor6_defs_.end()) {
|
||||
// No such vendor-id space
|
||||
@ -737,6 +742,12 @@ LibDHCP::initVendorOptsDocsis6() {
|
||||
initOptionSpace(vendor6_defs_[VENDOR_ID_CABLE_LABS], DOCSIS3_V6_DEFS, DOCSIS3_V6_DEFS_SIZE);
|
||||
}
|
||||
|
||||
void
|
||||
LibDHCP::initVendorOptsIsc6() {
|
||||
vendor6_defs_[ENTERPRISE_ID_ISC] = OptionDefContainer();
|
||||
initOptionSpace(vendor6_defs_[ENTERPRISE_ID_ISC], ISC_V6_DEFS, ISC_V6_DEFS_SIZE);
|
||||
}
|
||||
|
||||
void initOptionSpace(OptionDefContainer& defs,
|
||||
const OptionDefParams* params,
|
||||
size_t params_size) {
|
||||
|
@ -281,6 +281,9 @@ private:
|
||||
|
||||
static void initVendorOptsDocsis6();
|
||||
|
||||
/// Initialize private DHCPv6 option definitions.
|
||||
static void initVendorOptsIsc6();
|
||||
|
||||
/// pointers to factories that produce DHCPv6 options
|
||||
static FactoryMap v4factories_;
|
||||
|
||||
|
@ -50,10 +50,10 @@ Pkt::Pkt(const uint8_t* buf, uint32_t len, const isc::asiolink::IOAddress& local
|
||||
{
|
||||
|
||||
if (len != 0) {
|
||||
if (buf == NULL) {
|
||||
isc_throw(InvalidParameter, "data buffer passed to Pkt is NULL");
|
||||
}
|
||||
data_.resize(len);
|
||||
if (buf == NULL) {
|
||||
isc_throw(InvalidParameter, "data buffer passed to Pkt is NULL");
|
||||
}
|
||||
data_.resize(len);
|
||||
memcpy(&data_[0], buf, len);
|
||||
}
|
||||
}
|
||||
|
@ -375,6 +375,14 @@ public:
|
||||
/// (true) or non-relayed (false).
|
||||
bool isRelayed() const;
|
||||
|
||||
/// @brief Checks if a DHCPv4 message has beeb transported over DHCPv6
|
||||
///
|
||||
/// @return Boolean value which indicates whether the message is
|
||||
/// transported over DHCPv6 (true) or native DHCPv4 (false)
|
||||
virtual bool isDhcp4o6() const {
|
||||
return (false);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Generic method that validates and sets HW address.
|
||||
|
60
src/lib/dhcp/pkt4o6.cc
Normal file
60
src/lib/dhcp/pkt4o6.cc
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright (C) 2015 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 <config.h>
|
||||
|
||||
#include <dhcp/dhcp6.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <dhcp/pkt4o6.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
#include <util/buffer.h>
|
||||
|
||||
using namespace isc::asiolink;
|
||||
using namespace isc::dhcp;
|
||||
using namespace isc::util;
|
||||
using namespace std;
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
Pkt4o6::Pkt4o6(const OptionBuffer& pkt4, const Pkt6Ptr& pkt6)
|
||||
:Pkt4(&pkt4[0], pkt4.size()), pkt6_(pkt6)
|
||||
{
|
||||
static_cast<void>(pkt6->delOption(D6O_DHCPV4_MSG));
|
||||
setIface(pkt6->getIface());
|
||||
setIndex(pkt6->getIndex());
|
||||
setRemoteAddr(pkt6->getRemoteAddr());
|
||||
}
|
||||
|
||||
Pkt4o6::Pkt4o6(const Pkt4Ptr& pkt4, const Pkt6Ptr& pkt6)
|
||||
:Pkt4(*pkt4), pkt6_(pkt6) {
|
||||
}
|
||||
|
||||
void Pkt4o6::pack() {
|
||||
// Convert wire-format Pkt4 data in the form of OptionBuffer.
|
||||
Pkt4::pack();
|
||||
OutputBuffer& buf = getBuffer();
|
||||
const uint8_t* ptr = static_cast<const uint8_t*>(buf.getData());
|
||||
OptionBuffer msg(ptr, ptr + buf.getLength());
|
||||
|
||||
// Build the DHCPv4 Message option for the DHCPv6 message, and pack the
|
||||
// entire stuff.
|
||||
OptionPtr dhcp4_msg(new Option(Option::V6, D6O_DHCPV4_MSG, msg));
|
||||
pkt6_->addOption(dhcp4_msg);
|
||||
pkt6_->pack();
|
||||
}
|
||||
|
||||
} // end of namespace isc::dhcp
|
||||
|
||||
} // end of namespace isc
|
83
src/lib/dhcp/pkt4o6.h
Normal file
83
src/lib/dhcp/pkt4o6.h
Normal file
@ -0,0 +1,83 @@
|
||||
// Copyright (C) 2015 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 PKT4O6_H
|
||||
#define PKT4O6_H
|
||||
|
||||
#include <dhcp/pkt4.h>
|
||||
#include <dhcp/pkt6.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace isc {
|
||||
|
||||
namespace dhcp {
|
||||
|
||||
/// @brief Represents DHCPv4-over-DHCPv6 packet
|
||||
///
|
||||
/// This class derives from @c Pkt4 in order to be handled by
|
||||
/// the DHCPv4 server code. It includes a shared pointer to the
|
||||
/// DHCPv6 message too.
|
||||
///
|
||||
/// This is an implementation of the DHCPv4-query/response DHCPv6 messages
|
||||
/// defined in RFC 7341 (http://ietf.org/rfc/rfc7341.txt).
|
||||
/// See also http://kea.isc.org/wiki/Dhcp4o6Design for design discussions.
|
||||
class Pkt4o6 : public Pkt4 {
|
||||
public:
|
||||
|
||||
/// @brief Constructor, used in message reception.
|
||||
///
|
||||
/// @param pkt4 Content of the DHCPv4-message option
|
||||
/// @param pkt6 encapsulating unpacked DHCPv6 message
|
||||
/// the DHCPv4 message option will be removed
|
||||
Pkt4o6(const OptionBuffer& pkt4, const Pkt6Ptr& pkt6);
|
||||
|
||||
/// @brief Constructor, used in replying to a message
|
||||
///
|
||||
/// @param pkt4 DHCPv4 message
|
||||
/// @param pkt6 DHCPv6 message
|
||||
Pkt4o6(const Pkt4Ptr& pkt4, const Pkt6Ptr& pkt6);
|
||||
|
||||
/// @brief Returns encapsulating DHCPv6 message
|
||||
Pkt6Ptr getPkt6() const { return (pkt6_); }
|
||||
|
||||
/// @brief Prepares on-wire format of DHCPv4-over-DHCPv6 packet.
|
||||
///
|
||||
/// Calls pack() on both DHCPv4 and DHCPv6 parts
|
||||
/// Inserts the DHCPv4-message option
|
||||
/// @ref Pkt4::pack and @ref Pkt6::pack
|
||||
virtual void pack();
|
||||
|
||||
/// @brief Checks if a DHCPv4 message has been transported over DHCPv6
|
||||
///
|
||||
/// @return Boolean value which indicates whether the message is
|
||||
/// transported over DHCPv6 (true) or native DHCPv4 (false)
|
||||
virtual bool isDhcp4o6() const {
|
||||
return (true);
|
||||
}
|
||||
|
||||
private:
|
||||
/// Encapsulating DHCPv6 message
|
||||
Pkt6Ptr pkt6_;
|
||||
|
||||
}; // Pkt4o6 class
|
||||
|
||||
/// @brief A pointer to Pkt4o6 object.
|
||||
typedef boost::shared_ptr<Pkt4o6> Pkt4o6Ptr;
|
||||
|
||||
} // isc::dhcp namespace
|
||||
|
||||
} // isc namespace
|
||||
|
||||
#endif
|
@ -289,6 +289,8 @@ Pkt6::unpackUDP() {
|
||||
case DHCPV6_DECLINE:
|
||||
case DHCPV6_RECONFIGURE:
|
||||
case DHCPV6_INFORMATION_REQUEST:
|
||||
case DHCPV6_DHCPV4_QUERY:
|
||||
case DHCPV6_DHCPV4_RESPONSE:
|
||||
default: // assume that uknown messages are not using relay format
|
||||
{
|
||||
return (unpackMsg(data_.begin(), data_.end()));
|
||||
@ -586,6 +588,8 @@ Pkt6::getName(const uint8_t type) {
|
||||
static const char* REPLY = "REPLY";
|
||||
static const char* REQUEST = "REQUEST";
|
||||
static const char* SOLICIT = "SOLICIT";
|
||||
static const char* DHCPV4_QUERY = "DHCPV4_QUERY";
|
||||
static const char* DHCPV4_RESPONSE = "DHCPV4_RESPONSE";
|
||||
static const char* UNKNOWN = "UNKNOWN";
|
||||
|
||||
switch (type) {
|
||||
@ -634,6 +638,12 @@ Pkt6::getName(const uint8_t type) {
|
||||
case DHCPV6_SOLICIT:
|
||||
return (SOLICIT);
|
||||
|
||||
case DHCPV6_DHCPV4_QUERY:
|
||||
return (DHCPV4_QUERY);
|
||||
|
||||
case DHCPV6_DHCPV4_RESPONSE:
|
||||
return (DHCPV4_RESPONSE);
|
||||
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
@ -353,6 +353,9 @@ const OptionDefParams OPTION_DEF_PARAMS6[] = {
|
||||
{ "rsoo", D6O_RSOO, OPT_EMPTY_TYPE, false, NO_RECORD_DEF, "rsoo-opts" },
|
||||
{ "client-linklayer-addr", D6O_CLIENT_LINKLAYER_ADDR, OPT_BINARY_TYPE, false,
|
||||
NO_RECORD_DEF, "" },
|
||||
{ "dhcpv4-message", D6O_DHCPV4_MSG, OPT_BINARY_TYPE, false, NO_RECORD_DEF, "" },
|
||||
{ "dhcp4o6-server-addr", D6O_DHCPV4_O_DHCPV6_SERVER, OPT_IPV6_ADDRESS_TYPE, true,
|
||||
NO_RECORD_DEF, "" },
|
||||
{ "public-key", D6O_PUBLIC_KEY, OPT_BINARY_TYPE, false,
|
||||
NO_RECORD_DEF, "" },
|
||||
{ "certificate", D6O_CERTIFICATE, OPT_BINARY_TYPE, false,
|
||||
@ -371,6 +374,19 @@ const OptionDefParams OPTION_DEF_PARAMS6[] = {
|
||||
const int OPTION_DEF_PARAMS_SIZE6 =
|
||||
sizeof(OPTION_DEF_PARAMS6) / sizeof(OPTION_DEF_PARAMS6[0]);
|
||||
|
||||
/// @brief Definitions of vendor-specific DHCPv6 options, defined by ISC.
|
||||
/// 4o6-* options are used for inter-process communication. For details, see
|
||||
/// http://kea.isc.org/wiki/Dhcp4o6Design
|
||||
///
|
||||
/// @todo: As those options are defined by ISC, they do not belong in std_option_defs.h.
|
||||
/// We need to move them to a separate file, e.g. isc_option_defs.h
|
||||
const OptionDefParams ISC_V6_DEFS[] = {
|
||||
{ "4o6-interface", ISC_V6_4O6_INTERFACE, OPT_STRING_TYPE, false, NO_RECORD_DEF, "" },
|
||||
{ "4o6-source-address", ISC_V6_4O6_SRC_ADDRESS, OPT_IPV6_ADDRESS_TYPE, false, NO_RECORD_DEF, "" }
|
||||
};
|
||||
|
||||
const int ISC_V6_DEFS_SIZE = sizeof(ISC_V6_DEFS) / sizeof(OptionDefParams);
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
} // namespace dhcp
|
||||
|
@ -74,6 +74,7 @@ libdhcp___unittests_SOURCES += option_vendor_class_unittest.cc
|
||||
libdhcp___unittests_SOURCES += pkt_captures4.cc pkt_captures6.cc pkt_captures.h
|
||||
libdhcp___unittests_SOURCES += pkt4_unittest.cc
|
||||
libdhcp___unittests_SOURCES += pkt6_unittest.cc
|
||||
libdhcp___unittests_SOURCES += pkt4o6_unittest.cc
|
||||
libdhcp___unittests_SOURCES += pkt_filter_unittest.cc
|
||||
libdhcp___unittests_SOURCES += pkt_filter_inet_unittest.cc
|
||||
libdhcp___unittests_SOURCES += pkt_filter_inet6_unittest.cc
|
||||
|
@ -1200,6 +1200,12 @@ TEST_F(LibDhcpTest, stdOptionDefs6) {
|
||||
fqdn_buf.begin(), fqdn_buf.end(),
|
||||
typeid(OptionCustom));
|
||||
|
||||
LibDhcpTest::testStdOptionDefs6(D6O_DHCPV4_MSG, begin, end,
|
||||
typeid(Option));
|
||||
|
||||
LibDhcpTest::testStdOptionDefs6(D6O_DHCPV4_O_DHCPV6_SERVER, begin, end,
|
||||
typeid(Option6AddrLst));
|
||||
|
||||
LibDhcpTest::testStdOptionDefs6(D6O_PUBLIC_KEY, begin, end,
|
||||
typeid(Option));
|
||||
|
||||
|
106
src/lib/dhcp/tests/pkt4o6_unittest.cc
Normal file
106
src/lib/dhcp/tests/pkt4o6_unittest.cc
Normal file
@ -0,0 +1,106 @@
|
||||
// Copyright (C) 2015 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 <config.h>
|
||||
|
||||
#include <dhcp/dhcp6.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <dhcp/pkt4.h>
|
||||
#include <dhcp/pkt6.h>
|
||||
#include <dhcp/pkt4o6.h>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace isc::dhcp;
|
||||
|
||||
namespace {
|
||||
|
||||
/// @brief A Fixture class dedicated to testing of the Pkt4o6 class that
|
||||
/// represents a DHCPv4-over-DHCPv6 packet.
|
||||
class Pkt4o6Test : public ::testing::Test {
|
||||
protected:
|
||||
Pkt4o6Test() :
|
||||
data6_(6, 0),
|
||||
pkt6_(new Pkt6(&data6_[0], data6_.size())),
|
||||
pkt4_(new Pkt4(DHCPDISCOVER, 0x12345678))
|
||||
{
|
||||
pkt4_->pack();
|
||||
const uint8_t* cp = static_cast<const uint8_t*>(
|
||||
pkt4_->getBuffer().getData());
|
||||
buffer4_.assign(cp, cp + pkt4_->getBuffer().getLength());
|
||||
}
|
||||
|
||||
protected:
|
||||
// commonly used test data
|
||||
const std::vector<uint8_t> data6_; // data for Pkt6 (content unimportant)
|
||||
Pkt6Ptr pkt6_; // DHCPv6 message for 4o6
|
||||
Pkt4Ptr pkt4_; // DHCPv4 message for 4o6
|
||||
OptionBuffer buffer4_; // wire-format data buffer of pkt4_
|
||||
};
|
||||
|
||||
// This test verifies that the constructors are working as expected.
|
||||
TEST_F(Pkt4o6Test, construct) {
|
||||
// Construct 4o6 packet, unpack the data to examine it
|
||||
boost::scoped_ptr<Pkt4o6> pkt4o6(new Pkt4o6(buffer4_, pkt6_));
|
||||
pkt4o6->unpack();
|
||||
// Inspect its internal to confirm it's built as expected. We also test
|
||||
// isDhcp4o6() here.
|
||||
EXPECT_TRUE(pkt4o6->isDhcp4o6());
|
||||
EXPECT_EQ(pkt6_, pkt4o6->getPkt6());
|
||||
EXPECT_EQ(DHCPDISCOVER, pkt4o6->getType());
|
||||
|
||||
// Same check for the other constructor. It relies on the internal
|
||||
// behavior of Pkt4's copy constructor, so we need to first unpack pkt4.
|
||||
pkt4_.reset(new Pkt4(&buffer4_[0], buffer4_.size()));
|
||||
pkt4_->unpack();
|
||||
pkt4o6.reset(new Pkt4o6(pkt4_, pkt6_));
|
||||
EXPECT_TRUE(pkt4o6->isDhcp4o6());
|
||||
EXPECT_EQ(pkt6_, pkt4o6->getPkt6());
|
||||
EXPECT_EQ(DHCPDISCOVER, pkt4o6->getType());
|
||||
}
|
||||
|
||||
// This test verifies that the pack() method handles the building
|
||||
// process correctly.
|
||||
TEST_F(Pkt4o6Test, pack) {
|
||||
// prepare unpacked DHCPv4 packet (see the note in constructor test)
|
||||
pkt4_.reset(new Pkt4(&buffer4_[0], buffer4_.size()));
|
||||
pkt4_->unpack();
|
||||
|
||||
// Construct 4o6 packet to be tested and pack the data.
|
||||
Pkt4o6 pkt4o6(pkt4_, pkt6_);
|
||||
pkt4o6.pack();
|
||||
|
||||
// The packed data should be:
|
||||
// 4-byte DHCPv6 message header
|
||||
// 4-byte header part of DHCPv4 message option
|
||||
// Raw DHCPv4 message (data stored in buffer4_)
|
||||
EXPECT_EQ(4 + 4 + buffer4_.size(),
|
||||
pkt4o6.getPkt6()->getBuffer().getLength());
|
||||
|
||||
// Check the DHCPv4 message option content (Pkt4o6 class is not responsible
|
||||
// for making it valid, so we won't examine it)
|
||||
const uint8_t* cp = static_cast<const uint8_t*>(
|
||||
pkt4o6.getPkt6()->getBuffer().getData());
|
||||
EXPECT_EQ(0, cp[4]);
|
||||
EXPECT_EQ(D6O_DHCPV4_MSG, cp[5]);
|
||||
EXPECT_EQ((buffer4_.size() >> 8) & 0xff, cp[6]);
|
||||
EXPECT_EQ(buffer4_.size() & 0xff, cp[7]);
|
||||
EXPECT_EQ(0, memcmp(&cp[8], &buffer4_[0], buffer4_.size()));
|
||||
}
|
||||
|
||||
/// @todo: Add a test that handles actual DHCP4o6 traffic capture
|
||||
/// once we get it. We should add the capture to pkt_captures{4,6}.cc
|
||||
}
|
@ -594,6 +594,14 @@ TEST_F(Pkt6Test, getName) {
|
||||
EXPECT_STREQ("DECLINE", Pkt6::getName(type));
|
||||
break;
|
||||
|
||||
case DHCPV6_DHCPV4_QUERY:
|
||||
EXPECT_STREQ("DHCPV4_QUERY", Pkt6::getName(type));
|
||||
break;
|
||||
|
||||
case DHCPV6_DHCPV4_RESPONSE:
|
||||
EXPECT_STREQ("DHCPV4_RESPONSE", Pkt6::getName(type));
|
||||
break;
|
||||
|
||||
case DHCPV6_INFORMATION_REQUEST:
|
||||
EXPECT_STREQ("INFORMATION_REQUEST",
|
||||
Pkt6::getName(type));
|
||||
|
@ -593,7 +593,7 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
|
||||
// The decodeHex function expects that the string contains an
|
||||
// even number of digits. If we don't meet this requirement,
|
||||
// we have to insert a leading 0.
|
||||
if (!data_param.empty() && data_param.length() % 2) {
|
||||
if (!data_param.empty() && ((data_param.length() % 2) != 0)) {
|
||||
data_param = data_param.insert(0, "0");
|
||||
}
|
||||
util::encode::decodeHex(data_param, binary);
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2013-2015 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
|
||||
@ -745,6 +745,7 @@ private:
|
||||
|
||||
/// Instance of option definition being created by this parser.
|
||||
OptionDefinitionPtr option_definition_;
|
||||
|
||||
/// Name of the space the option definition belongs to.
|
||||
std::string option_space_name_;
|
||||
|
||||
|
@ -507,6 +507,83 @@ private:
|
||||
/// @brief A generic pointer to either Subnet4 or Subnet6 object
|
||||
typedef boost::shared_ptr<Subnet> SubnetPtr;
|
||||
|
||||
/// @brief This structure contains information about DHCP4o6 (RFC7341)
|
||||
///
|
||||
/// DHCP4o6 is completely optional. If it is not enabled, this structure
|
||||
/// does not contain any information.
|
||||
struct Cfg4o6 {
|
||||
|
||||
/// the default constructor.
|
||||
///
|
||||
/// Initializes fields to their default value.
|
||||
Cfg4o6()
|
||||
:enabled_(false), subnet4o6_(std::make_pair(asiolink::IOAddress("::"), 128u)) {
|
||||
}
|
||||
|
||||
/// @brief Returns whether the DHCP4o6 is enabled or not.
|
||||
/// @return true if enabled
|
||||
bool enabled() const {
|
||||
return (enabled_);
|
||||
}
|
||||
|
||||
/// @brief Sets the DHCP4o6 enabled status.
|
||||
/// @param enabled specifies if the DHCP4o6 should be enabled or not
|
||||
void enabled(bool enabled) {
|
||||
enabled_ = enabled;
|
||||
}
|
||||
|
||||
/// @brief Returns the DHCP4o6 interface.
|
||||
/// @return value of the 4o6-interface parameter.
|
||||
std::string getIface4o6() const {
|
||||
return (iface4o6_);
|
||||
}
|
||||
|
||||
/// @brief Sets the 4o6-interface.
|
||||
/// @param iface name of the network interface the 4o6 traffic is received on
|
||||
void setIface4o6(const std::string& iface) {
|
||||
iface4o6_ = iface;
|
||||
}
|
||||
|
||||
/// @brief Returns prefix/len for the IPv6 subnet.
|
||||
/// @return prefix/length pair
|
||||
std::pair<asiolink::IOAddress, uint8_t> getSubnet4o6() const {
|
||||
return (subnet4o6_);
|
||||
}
|
||||
|
||||
/// @brief Sets the prefix/length information (content of the 4o6-subnet).
|
||||
/// @param subnet IOAddress that represents a prefix
|
||||
/// @param prefix specifies prefix length
|
||||
void setSubnet4o6(const asiolink::IOAddress& subnet, uint8_t prefix) {
|
||||
subnet4o6_ = std::make_pair(subnet, prefix);
|
||||
}
|
||||
|
||||
/// @brief Returns the interface-id.
|
||||
/// @return the option representing interface-id (or NULL)
|
||||
OptionPtr getInterfaceId() const {
|
||||
return (interface_id_);
|
||||
}
|
||||
|
||||
/// @brief Sets the interface-id
|
||||
/// @param opt option to be used as interface-id match
|
||||
void setInterfaceId(const OptionPtr& opt) {
|
||||
interface_id_ = opt;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// Specifies if 4o6 is enabled on this subnet.
|
||||
bool enabled_;
|
||||
|
||||
/// Specifies the network interface used as v4 subnet selector.
|
||||
std::string iface4o6_;
|
||||
|
||||
/// Specifies the IPv6 subnet used for v4 subnet selection.
|
||||
std::pair<asiolink::IOAddress, uint8_t> subnet4o6_;
|
||||
|
||||
/// Specifies the v6 interface-id used for v4 subnet selection.
|
||||
OptionPtr interface_id_;
|
||||
};
|
||||
|
||||
/// @brief A configuration holder for IPv4 subnet.
|
||||
///
|
||||
/// This class represents an IPv4 subnet.
|
||||
@ -559,6 +636,14 @@ public:
|
||||
return (match_client_id_);
|
||||
}
|
||||
|
||||
/// @brief Returns DHCP4o6 configuration parameters.
|
||||
///
|
||||
/// This structure is always available. If the 4o6 is not enabled, its
|
||||
/// enabled_ field will be set to false.
|
||||
Cfg4o6& get4o6() {
|
||||
return (dhcp4o6_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Returns default address for pool selection
|
||||
@ -581,6 +666,9 @@ private:
|
||||
/// @brief Should server use client identifiers for client lease
|
||||
/// lookup.
|
||||
bool match_client_id_;
|
||||
|
||||
/// @brief All the information related to DHCP4o6
|
||||
Cfg4o6 dhcp4o6_;
|
||||
};
|
||||
|
||||
/// @brief A pointer to a @c Subnet4 object
|
||||
|
@ -458,10 +458,10 @@ public:
|
||||
std::string error_text_;
|
||||
};
|
||||
|
||||
/// @brief Check Basic parsing of option definitions.
|
||||
/// @brief Check basic parsing of option definitions.
|
||||
///
|
||||
/// Note that this tests basic operation of the OptionDefinitionListParser and
|
||||
/// OptionDefinitionParser. It uses a simple configuration consisting of one
|
||||
/// OptionDefinitionParser. It uses a simple configuration consisting of
|
||||
/// one definition and verifies that it is parsed and committed to storage
|
||||
/// correctly.
|
||||
TEST_F(ParseConfigTest, basicOptionDefTest) {
|
||||
@ -481,7 +481,7 @@ TEST_F(ParseConfigTest, basicOptionDefTest) {
|
||||
|
||||
// Verify that the configuration string parses.
|
||||
int rcode = parseConfiguration(config);
|
||||
ASSERT_TRUE(rcode == 0);
|
||||
ASSERT_EQ(0, rcode);
|
||||
|
||||
|
||||
// Verify that the option definition can be retrieved.
|
||||
@ -497,7 +497,73 @@ TEST_F(ParseConfigTest, basicOptionDefTest) {
|
||||
EXPECT_TRUE(def->getEncapsulatedSpace().empty());
|
||||
}
|
||||
|
||||
/// @brief Check Basic parsing of options.
|
||||
/// @brief Check minimal parsing of option definitions.
|
||||
///
|
||||
/// Same than basic but without optional parameters set to their default.
|
||||
TEST_F(ParseConfigTest, minimalOptionDefTest) {
|
||||
|
||||
// Configuration string.
|
||||
std::string config =
|
||||
"{ \"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"space\": \"isc\""
|
||||
" } ]"
|
||||
"}";
|
||||
|
||||
// Verify that the configuration string parses.
|
||||
int rcode = parseConfiguration(config);
|
||||
ASSERT_EQ(0, rcode);
|
||||
|
||||
|
||||
// Verify that the option definition can be retrieved.
|
||||
OptionDefinitionPtr def =
|
||||
CfgMgr::instance().getStagingCfg()->getCfgOptionDef()->get("isc", 100);
|
||||
ASSERT_TRUE(def);
|
||||
|
||||
// Verify that the option definition is correct.
|
||||
EXPECT_EQ("foo", def->getName());
|
||||
EXPECT_EQ(100, def->getCode());
|
||||
EXPECT_FALSE(def->getArrayType());
|
||||
EXPECT_EQ(OPT_IPV4_ADDRESS_TYPE, def->getType());
|
||||
EXPECT_TRUE(def->getEncapsulatedSpace().empty());
|
||||
}
|
||||
|
||||
/// @brief Check parsing of option definitions using default dhcp6 space.
|
||||
///
|
||||
/// Same than minimal but using the fact the default universe is V6
|
||||
/// so the default space is dhcp6
|
||||
TEST_F(ParseConfigTest, defaultSpaceOptionDefTest) {
|
||||
|
||||
// Configuration string.
|
||||
std::string config =
|
||||
"{ \"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 10000,"
|
||||
" \"type\": \"ipv6-address\""
|
||||
" } ]"
|
||||
"}";
|
||||
|
||||
// Verify that the configuration string parses.
|
||||
int rcode = parseConfiguration(config);
|
||||
ASSERT_EQ(0, rcode);
|
||||
|
||||
|
||||
// Verify that the option definition can be retrieved.
|
||||
OptionDefinitionPtr def =
|
||||
CfgMgr::instance().getStagingCfg()->getCfgOptionDef()->get("dhcp6", 10000);
|
||||
ASSERT_TRUE(def);
|
||||
|
||||
// Verify that the option definition is correct.
|
||||
EXPECT_EQ("foo", def->getName());
|
||||
EXPECT_EQ(10000, def->getCode());
|
||||
EXPECT_FALSE(def->getArrayType());
|
||||
EXPECT_EQ(OPT_IPV6_ADDRESS_TYPE, def->getType());
|
||||
EXPECT_TRUE(def->getEncapsulatedSpace().empty());
|
||||
}
|
||||
|
||||
/// @brief Check basic parsing of options.
|
||||
///
|
||||
/// Note that this tests basic operation of the OptionDataListParser and
|
||||
/// OptionDataParser. It uses a simple configuration consisting of one
|
||||
@ -511,10 +577,7 @@ TEST_F(ParseConfigTest, basicOptionDataTest) {
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"array\": False,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"isc\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"isc\""
|
||||
" } ], "
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
@ -527,13 +590,47 @@ TEST_F(ParseConfigTest, basicOptionDataTest) {
|
||||
|
||||
// Verify that the configuration string parses.
|
||||
int rcode = parseConfiguration(config);
|
||||
ASSERT_TRUE(rcode == 0);
|
||||
ASSERT_EQ(0, rcode);
|
||||
|
||||
// Verify that the option can be retrieved.
|
||||
OptionPtr opt_ptr = getOptionPtr("isc", 100);
|
||||
ASSERT_TRUE(opt_ptr);
|
||||
|
||||
// Verify that the option definition is correct.
|
||||
// Verify that the option data is correct.
|
||||
std::string val = "type=00100, len=00004: 192.0.2.0 (ipv4-address)";
|
||||
|
||||
EXPECT_EQ(val, opt_ptr->toText());
|
||||
}
|
||||
|
||||
/// @brief Check minimal parsing of options.
|
||||
///
|
||||
/// Same than basic but without optional parameters set to their default.
|
||||
TEST_F(ParseConfigTest, minimalOptionDataTest) {
|
||||
|
||||
// Configuration string.
|
||||
std::string config =
|
||||
"{ \"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 100,"
|
||||
" \"type\": \"ipv4-address\","
|
||||
" \"space\": \"isc\""
|
||||
" } ], "
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"space\": \"isc\","
|
||||
" \"data\": \"192.0.2.0\""
|
||||
" } ]"
|
||||
"}";
|
||||
|
||||
// Verify that the configuration string parses.
|
||||
int rcode = parseConfiguration(config);
|
||||
ASSERT_EQ(0, rcode);
|
||||
|
||||
// Verify that the option can be retrieved.
|
||||
OptionPtr opt_ptr = getOptionPtr("isc", 100);
|
||||
ASSERT_TRUE(opt_ptr);
|
||||
|
||||
// Verify that the option data is correct.
|
||||
std::string val = "type=00100, len=00004: 192.0.2.0 (ipv4-address)";
|
||||
|
||||
EXPECT_EQ(val, opt_ptr->toText());
|
||||
@ -690,7 +787,6 @@ TEST_F(ParseConfigTest, optionDataNoName) {
|
||||
"{ \"option-data\": [ {"
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"code\": 23,"
|
||||
" \"csv-format\": True,"
|
||||
" \"data\": \"2001:db8:1::1\""
|
||||
" } ]"
|
||||
"}";
|
||||
@ -711,7 +807,6 @@ TEST_F(ParseConfigTest, optionDataNoCode) {
|
||||
"{ \"option-data\": [ {"
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"name\": \"dns-servers\","
|
||||
" \"csv-format\": True,"
|
||||
" \"data\": \"2001:db8:1::1\""
|
||||
" } ]"
|
||||
"}";
|
||||
@ -772,9 +867,7 @@ TEST_F(ParseConfigTest, optionDataMinimalWithOptionDef) {
|
||||
" \"code\": 2345,"
|
||||
" \"type\": \"ipv6-address\","
|
||||
" \"array\": True,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"dhcp6\""
|
||||
" } ],"
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"foo-name\","
|
||||
@ -800,9 +893,7 @@ TEST_F(ParseConfigTest, optionDataMinimalWithOptionDef) {
|
||||
" \"code\": 2345,"
|
||||
" \"type\": \"ipv6-address\","
|
||||
" \"array\": True,"
|
||||
" \"record-types\": \"\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"encapsulate\": \"\""
|
||||
" \"space\": \"dhcp6\""
|
||||
" } ],"
|
||||
" \"option-data\": [ {"
|
||||
" \"code\": 2345,"
|
||||
|
@ -12,18 +12,25 @@ AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
|
||||
|
||||
lib_LTLIBRARIES = libkea-eval.la
|
||||
libkea_eval_la_SOURCES =
|
||||
libkea_eval_la_SOURCES += eval_log.cc eval_log.h
|
||||
libkea_eval_la_SOURCES += token.cc token.h
|
||||
|
||||
libkea_eval_la_SOURCES += parser.cc parser.h
|
||||
libkea_eval_la_SOURCES += lexer.cc
|
||||
libkea_eval_la_SOURCES += eval_context.cc
|
||||
|
||||
nodist_libkea_eval_la_SOURCES = eval_messages.h eval_messages.cc
|
||||
|
||||
libkea_eval_la_CXXFLAGS = $(AM_CXXFLAGS)
|
||||
libkea_eval_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
libkea_eval_la_LIBADD = $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
|
||||
libkea_eval_la_LIBADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
|
||||
libkea_eval_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la
|
||||
libkea_eval_la_LIBADD += $(top_builddir)/src/lib/util/libkea-util.la
|
||||
libkea_eval_la_LIBADD += $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS)
|
||||
|
||||
libkea_eval_la_LDFLAGS = -no-undefined -version-info 3:0:0
|
||||
libkea_eval_la_LDFLAGS += $(LOG4CPLUS_LIBS) $(CRYPTO_LDFLAGS)
|
||||
libkea_eval_la_LDFLAGS += $(CRYPTO_LDFLAGS)
|
||||
|
||||
EXTRA_DIST = eval.dox
|
||||
EXTRA_DIST += eval_messages.mes
|
||||
@ -33,6 +40,7 @@ eval_messages.h eval_messages.cc: s-messages
|
||||
|
||||
s-messages: eval_messages.mes
|
||||
$(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/eval/eval_messages.mes
|
||||
touch $@
|
||||
|
||||
# Tell Automake that the eval_messages.{cc,h} source files are created in the
|
||||
# build process, so it must create these before doing anything else. Although
|
||||
@ -43,7 +51,7 @@ s-messages: eval_messages.mes
|
||||
# first.
|
||||
BUILT_SOURCES = eval_messages.h eval_messages.cc
|
||||
|
||||
CLEANFILES = eval_messages.h eval_messages.cc
|
||||
CLEANFILES = eval_messages.h eval_messages.cc s-messages
|
||||
|
||||
# If we want to get rid of all flex/bison generated files, we need to use
|
||||
# make maintainer-clean. The proper way to introduce custom commands for
|
||||
|
26
src/lib/eval/eval_log.cc
Normal file
26
src/lib/eval/eval_log.cc
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (C) 2015 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.
|
||||
|
||||
/// Defines the logger used by the Eval (classification) code
|
||||
|
||||
#include <eval/eval_log.h>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
isc::log::Logger eval_logger("eval");
|
||||
|
||||
} // namespace dhcp
|
||||
} // namespace isc
|
||||
|
49
src/lib/eval/eval_log.h
Normal file
49
src/lib/eval/eval_log.h
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright (C) 2015 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 EVAL_LOG_H
|
||||
#define EVAL_LOG_H
|
||||
|
||||
#include <log/macros.h>
|
||||
#include <eval/eval_messages.h>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
/// @brief Eval debug Logging levels
|
||||
///
|
||||
/// Defines the levels used to output debug messages in the eval (classification) code.
|
||||
/// Note that higher numbers equate to more verbose (and detailed) output.
|
||||
|
||||
// The first level traces normal operations,
|
||||
const int EVAL_DBG_TRACE = DBGLVL_TRACE_BASIC;
|
||||
|
||||
// The next level traces each call to hook code.
|
||||
const int EVAL_DBG_CALLS = DBGLVL_TRACE_BASIC_DATA;
|
||||
|
||||
// Additional information on the calls. Report each call to a callout (even
|
||||
// if there are multiple callouts on a hook) and each status return.
|
||||
const int EVAL_DBG_EXTENDED_CALLS = DBGLVL_TRACE_DETAIL_DATA;
|
||||
|
||||
/// @brief Eval Logger
|
||||
///
|
||||
/// Define the logger used to log messages. We could define it in multiple
|
||||
/// modules, but defining in a single module and linking to it saves time and
|
||||
/// space.
|
||||
extern isc::log::Logger eval_logger;
|
||||
|
||||
} // namespace dhcp
|
||||
} // namespace isc
|
||||
|
||||
#endif // EVAL_LOG_H
|
@ -18,3 +18,8 @@ $NAMESPACE isc::dhcp
|
||||
This debug message indicates that the expression has been evaluated
|
||||
to said value. This message is mostly useful during debugging of the
|
||||
client classification expressions.
|
||||
|
||||
% EVAL_SUBSTRING_BAD_PARAM_CONVERSION starting %1, length %2
|
||||
This debug message indicates that the parameter for the starting postion
|
||||
or length of the substring couldn't be converted to an integer. In this
|
||||
case the substring routine returns an empty string.
|
||||
|
@ -2,6 +2,8 @@ SUBDIRS = .
|
||||
|
||||
AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
|
||||
AM_CPPFLAGS += $(BOOST_INCLUDES)
|
||||
AM_CPPFLAGS += -DLOGGING_SPEC_FILE=\"$(abs_top_srcdir)/src/lib/dhcpsrv/logging.spec\"
|
||||
|
||||
AM_CXXFLAGS = $(KEA_CXXFLAGS)
|
||||
|
||||
# Some versions of GCC warn about some versions of Boost regarding
|
||||
@ -24,8 +26,9 @@ if HAVE_GTEST
|
||||
|
||||
TESTS += libeval_unittests
|
||||
|
||||
libeval_unittests_SOURCES = token_unittest.cc main.cc
|
||||
libeval_unittests_SOURCES += context_unittest.cc
|
||||
libeval_unittests_SOURCES = context_unittest.cc
|
||||
libeval_unittests_SOURCES += token_unittest.cc
|
||||
libeval_unittests_SOURCES += run_unittests.cc
|
||||
libeval_unittests_CXXFLAGS = $(AM_CXXFLAGS)
|
||||
libeval_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
|
||||
libeval_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS)
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace isc::dhcp;
|
||||
|
||||
@ -60,6 +62,40 @@ public:
|
||||
OptionPtr option_str4_; ///< A string option for DHCPv4
|
||||
OptionPtr option_str6_; ///< A string option for DHCPv6
|
||||
|
||||
|
||||
/// @brief Verify that the substring eval works properly
|
||||
///
|
||||
/// This function takes the parameters and sets up the value
|
||||
/// stack then executes the eval and checks the results.
|
||||
///
|
||||
/// @param test_string The string to operate on
|
||||
/// @param test_start The postion to start when getting a substring
|
||||
/// @param test_length The length of the substring to get
|
||||
/// @param result_string The expected result of the eval
|
||||
void verifySubstringEval(const std::string& test_string,
|
||||
const std::string& test_start,
|
||||
const std::string& test_length,
|
||||
const std::string& result_string) {
|
||||
|
||||
// create the token
|
||||
ASSERT_NO_THROW(t_.reset(new TokenSubstring()));
|
||||
|
||||
// push values on stack
|
||||
values_.push(test_string);
|
||||
values_.push(test_start);
|
||||
values_.push(test_length);
|
||||
|
||||
// evaluate the token
|
||||
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
||||
|
||||
// verify results
|
||||
ASSERT_EQ(1, values_.size());
|
||||
EXPECT_EQ(result_string, values_.top());
|
||||
|
||||
// remove result
|
||||
values_.pop();
|
||||
}
|
||||
|
||||
/// @todo: Add more option types here
|
||||
};
|
||||
|
||||
@ -93,6 +129,116 @@ TEST_F(TokenTest, string6) {
|
||||
EXPECT_EQ("foo", values_.top());
|
||||
}
|
||||
|
||||
// This simple test checks that a TokenHexString, representing a constant
|
||||
// string coded in hexadecimal, can be used in Pkt4 evaluation.
|
||||
// (The actual packet is not used)
|
||||
TEST_F(TokenTest, hexstring4) {
|
||||
TokenPtr empty;
|
||||
TokenPtr bad;
|
||||
TokenPtr nodigit;
|
||||
TokenPtr baddigit;
|
||||
TokenPtr bell;
|
||||
TokenPtr foo;
|
||||
TokenPtr cookie;
|
||||
|
||||
// Store constant empty hexstring "" ("") in the TokenHexString object.
|
||||
ASSERT_NO_THROW(empty.reset(new TokenHexString("")));
|
||||
// Store bad encoded hexstring "0abc" ("").
|
||||
ASSERT_NO_THROW(bad.reset(new TokenHexString("0abc")));
|
||||
// Store hexstring with no digits "0x" ("").
|
||||
ASSERT_NO_THROW(nodigit.reset(new TokenHexString("0x")));
|
||||
// Store hexstring with a bad hexdigit "0xxabc" ("").
|
||||
ASSERT_NO_THROW(baddigit.reset(new TokenHexString("0xxabc")));
|
||||
// Store hexstring with an odd number of hexdigits "0x7" ("\a").
|
||||
ASSERT_NO_THROW(bell.reset(new TokenHexString("0x7")));
|
||||
// Store constant hexstring "0x666f6f" ("foo").
|
||||
ASSERT_NO_THROW(foo.reset(new TokenHexString("0x666f6f")));
|
||||
// Store constant hexstring "0x63825363" (DHCP_OPTIONS_COOKIE).
|
||||
ASSERT_NO_THROW(cookie.reset(new TokenHexString("0x63825363")));
|
||||
|
||||
// Make sure that tokens can be evaluated without exceptions.
|
||||
ASSERT_NO_THROW(empty->evaluate(*pkt4_, values_));
|
||||
ASSERT_NO_THROW(bad->evaluate(*pkt4_, values_));
|
||||
ASSERT_NO_THROW(nodigit->evaluate(*pkt4_, values_));
|
||||
ASSERT_NO_THROW(baddigit->evaluate(*pkt4_, values_));
|
||||
ASSERT_NO_THROW(bell->evaluate(*pkt4_, values_));
|
||||
ASSERT_NO_THROW(foo->evaluate(*pkt4_, values_));
|
||||
ASSERT_NO_THROW(cookie->evaluate(*pkt4_, values_));
|
||||
|
||||
// Check that the evaluation put its value on the values stack.
|
||||
ASSERT_EQ(7, values_.size());
|
||||
uint32_t expected = htonl(DHCP_OPTIONS_COOKIE);
|
||||
EXPECT_EQ(4, values_.top().size());
|
||||
EXPECT_EQ(0, memcmp(&expected, &values_.top()[0], 4));
|
||||
values_.pop();
|
||||
EXPECT_EQ("foo", values_.top());
|
||||
values_.pop();
|
||||
EXPECT_EQ("\a", values_.top());
|
||||
values_.pop();
|
||||
EXPECT_EQ("", values_.top());
|
||||
values_.pop();
|
||||
EXPECT_EQ("", values_.top());
|
||||
values_.pop();
|
||||
EXPECT_EQ("", values_.top());
|
||||
values_.pop();
|
||||
EXPECT_EQ("", values_.top());
|
||||
}
|
||||
|
||||
// This simple test checks that a TokenHexString, representing a constant
|
||||
// string coded in hexadecimal, can be used in Pkt6 evaluation.
|
||||
// (The actual packet is not used)
|
||||
TEST_F(TokenTest, hexstring6) {
|
||||
TokenPtr empty;
|
||||
TokenPtr bad;
|
||||
TokenPtr nodigit;
|
||||
TokenPtr baddigit;
|
||||
TokenPtr bell;
|
||||
TokenPtr foo;
|
||||
TokenPtr cookie;
|
||||
|
||||
// Store constant empty hexstring "" ("") in the TokenHexString object.
|
||||
ASSERT_NO_THROW(empty.reset(new TokenHexString("")));
|
||||
// Store bad encoded hexstring "0abc" ("").
|
||||
ASSERT_NO_THROW(bad.reset(new TokenHexString("0abc")));
|
||||
// Store hexstring with no digits "0x" ("").
|
||||
ASSERT_NO_THROW(nodigit.reset(new TokenHexString("0x")));
|
||||
// Store hexstring with a bad hexdigit "0xxabc" ("").
|
||||
ASSERT_NO_THROW(baddigit.reset(new TokenHexString("0xxabc")));
|
||||
// Store hexstring with an odd number of hexdigits "0x7" ("\a").
|
||||
ASSERT_NO_THROW(bell.reset(new TokenHexString("0x7")));
|
||||
// Store constant hexstring "0x666f6f" ("foo").
|
||||
ASSERT_NO_THROW(foo.reset(new TokenHexString("0x666f6f")));
|
||||
// Store constant hexstring "0x63825363" (DHCP_OPTIONS_COOKIE).
|
||||
ASSERT_NO_THROW(cookie.reset(new TokenHexString("0x63825363")));
|
||||
|
||||
// Make sure that tokens can be evaluated without exceptions.
|
||||
ASSERT_NO_THROW(empty->evaluate(*pkt6_, values_));
|
||||
ASSERT_NO_THROW(bad->evaluate(*pkt6_, values_));
|
||||
ASSERT_NO_THROW(nodigit->evaluate(*pkt6_, values_));
|
||||
ASSERT_NO_THROW(baddigit->evaluate(*pkt6_, values_));
|
||||
ASSERT_NO_THROW(bell->evaluate(*pkt6_, values_));
|
||||
ASSERT_NO_THROW(foo->evaluate(*pkt6_, values_));
|
||||
ASSERT_NO_THROW(cookie->evaluate(*pkt6_, values_));
|
||||
|
||||
// Check that the evaluation put its value on the values stack.
|
||||
ASSERT_EQ(7, values_.size());
|
||||
uint32_t expected = htonl(DHCP_OPTIONS_COOKIE);
|
||||
EXPECT_EQ(4, values_.top().size());
|
||||
EXPECT_EQ(0, memcmp(&expected, &values_.top()[0], 4));
|
||||
values_.pop();
|
||||
EXPECT_EQ("foo", values_.top());
|
||||
values_.pop();
|
||||
EXPECT_EQ("\a", values_.top());
|
||||
values_.pop();
|
||||
EXPECT_EQ("", values_.top());
|
||||
values_.pop();
|
||||
EXPECT_EQ("", values_.top());
|
||||
values_.pop();
|
||||
EXPECT_EQ("", values_.top());
|
||||
values_.pop();
|
||||
EXPECT_EQ("", values_.top());
|
||||
}
|
||||
|
||||
// This test checks if a token representing an option value is able to extract
|
||||
// the option from an IPv4 packet and properly store the option's value.
|
||||
TEST_F(TokenTest, optionString4) {
|
||||
@ -197,3 +343,177 @@ TEST_F(TokenTest, optionEqualTrue) {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// This test checks if an a token representing a substring request
|
||||
// throws an exception if there aren't enough values on the stack.
|
||||
// The stack from the top is: length, start, string.
|
||||
// The actual packet is not used.
|
||||
TEST_F(TokenTest, substringNotEnoughValues) {
|
||||
ASSERT_NO_THROW(t_.reset(new TokenSubstring()));
|
||||
|
||||
// Subsring requires three values on the stack, try
|
||||
// with 0, 1 and 2 all should thorw an exception
|
||||
EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
|
||||
|
||||
values_.push("");
|
||||
EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
|
||||
|
||||
values_.push("0");
|
||||
EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
|
||||
|
||||
// Three should work
|
||||
values_.push("0");
|
||||
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
||||
|
||||
// As we had an empty string to start with we should have an empty
|
||||
// one after the evaluate
|
||||
ASSERT_EQ(1, values_.size());
|
||||
EXPECT_EQ("", values_.top());
|
||||
}
|
||||
|
||||
// Test getting the whole string in different ways
|
||||
TEST_F(TokenTest, substringWholeString) {
|
||||
// Get the whole string
|
||||
verifySubstringEval("foobar", "0", "6", "foobar");
|
||||
|
||||
// Get the whole string with "all"
|
||||
verifySubstringEval("foobar", "0", "all", "foobar");
|
||||
|
||||
// Get the whole string with an extra long number
|
||||
verifySubstringEval("foobar", "0", "123456", "foobar");
|
||||
|
||||
// Get the whole string counting from the back
|
||||
verifySubstringEval("foobar", "-6", "all", "foobar");
|
||||
}
|
||||
|
||||
// Test getting a suffix, in this case the last 3 characters
|
||||
TEST_F(TokenTest, substringTrailer) {
|
||||
verifySubstringEval("foobar", "3", "3", "bar");
|
||||
verifySubstringEval("foobar", "3", "all", "bar");
|
||||
verifySubstringEval("foobar", "-3", "all", "bar");
|
||||
verifySubstringEval("foobar", "-3", "123", "bar");
|
||||
}
|
||||
|
||||
// Test getting the middle of the string in different ways
|
||||
TEST_F(TokenTest, substringMiddle) {
|
||||
verifySubstringEval("foobar", "1", "4", "ooba");
|
||||
verifySubstringEval("foobar", "-5", "4", "ooba");
|
||||
verifySubstringEval("foobar", "-1", "-4", "ooba");
|
||||
verifySubstringEval("foobar", "5", "-4", "ooba");
|
||||
}
|
||||
|
||||
// Test getting the last letter in different ways
|
||||
TEST_F(TokenTest, substringLastLetter) {
|
||||
verifySubstringEval("foobar", "5", "all", "r");
|
||||
verifySubstringEval("foobar", "5", "1", "r");
|
||||
verifySubstringEval("foobar", "5", "5", "r");
|
||||
verifySubstringEval("foobar", "-1", "all", "r");
|
||||
verifySubstringEval("foobar", "-1", "1", "r");
|
||||
verifySubstringEval("foobar", "-1", "5", "r");
|
||||
}
|
||||
|
||||
// Test we get only what is available if we ask for a longer string
|
||||
TEST_F(TokenTest, substringLength) {
|
||||
// Test off the front
|
||||
verifySubstringEval("foobar", "0", "-4", "");
|
||||
verifySubstringEval("foobar", "1", "-4", "f");
|
||||
verifySubstringEval("foobar", "2", "-4", "fo");
|
||||
verifySubstringEval("foobar", "3", "-4", "foo");
|
||||
|
||||
// and the back
|
||||
verifySubstringEval("foobar", "3", "4", "bar");
|
||||
verifySubstringEval("foobar", "4", "4", "ar");
|
||||
verifySubstringEval("foobar", "5", "4", "r");
|
||||
verifySubstringEval("foobar", "6", "4", "");
|
||||
}
|
||||
|
||||
// Test that we get nothing if the starting postion is out of the string
|
||||
TEST_F(TokenTest, substringStartingPosition) {
|
||||
// Off the front
|
||||
verifySubstringEval("foobar", "-7", "1", "");
|
||||
verifySubstringEval("foobar", "-7", "-11", "");
|
||||
verifySubstringEval("foobar", "-7", "all", "");
|
||||
|
||||
// and the back
|
||||
verifySubstringEval("foobar", "6", "1", "");
|
||||
verifySubstringEval("foobar", "6", "-11", "");
|
||||
verifySubstringEval("foobar", "6", "all", "");
|
||||
}
|
||||
|
||||
// Check what happens if we use strings that aren't numbers for start or length
|
||||
// We should return the empty string
|
||||
TEST_F(TokenTest, substringBadParams) {
|
||||
verifySubstringEval("foobar", "0ick", "all", "");
|
||||
verifySubstringEval("foobar", "ick0", "all", "");
|
||||
verifySubstringEval("foobar", "ick", "all", "");
|
||||
verifySubstringEval("foobar", "0", "ick", "");
|
||||
verifySubstringEval("foobar", "0", "0ick", "");
|
||||
verifySubstringEval("foobar", "0", "ick0", "");
|
||||
verifySubstringEval("foobar", "0", "allaboard", "");
|
||||
}
|
||||
|
||||
// lastly check that we don't get anything if the string is empty or
|
||||
// we don't ask for any characters from it.
|
||||
TEST_F(TokenTest, substringReturnEmpty) {
|
||||
verifySubstringEval("", "0", "all", "");
|
||||
verifySubstringEval("foobar", "0", "0", "");
|
||||
}
|
||||
|
||||
// Check if we can use the substring and equal tokens together
|
||||
// We put the result on the stack first then the substring values
|
||||
// then evaluate the substring which should leave the original
|
||||
// result on the bottom with the substring result on next.
|
||||
// Evaulating the equals should produce true for the first
|
||||
// and false for the second.
|
||||
// throws an exception if there aren't enough values on the stack.
|
||||
// The stack from the top is: length, start, string.
|
||||
// The actual packet is not used.
|
||||
TEST_F(TokenTest, substringEquals) {
|
||||
TokenPtr tequal;
|
||||
|
||||
ASSERT_NO_THROW(t_.reset(new TokenSubstring()));
|
||||
ASSERT_NO_THROW(tequal.reset(new TokenEqual()));
|
||||
|
||||
// The final expected value
|
||||
values_.push("ooba");
|
||||
|
||||
// The substring values
|
||||
// Subsring requires three values on the stack, try
|
||||
// with 0, 1 and 2 all should thorw an exception
|
||||
values_.push("foobar");
|
||||
values_.push("1");
|
||||
values_.push("4");
|
||||
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
||||
|
||||
// we should have two values on the stack
|
||||
ASSERT_EQ(2, values_.size());
|
||||
|
||||
// next the equals eval
|
||||
EXPECT_NO_THROW(tequal->evaluate(*pkt4_, values_));
|
||||
ASSERT_EQ(1, values_.size());
|
||||
EXPECT_EQ("true", values_.top());
|
||||
|
||||
// get rid of the result
|
||||
values_.pop();
|
||||
|
||||
// and try it again but with a bad final value
|
||||
// The final expected value
|
||||
values_.push("foob");
|
||||
|
||||
// The substring values
|
||||
// Subsring requires three values on the stack, try
|
||||
// with 0, 1 and 2 all should thorw an exception
|
||||
values_.push("foobar");
|
||||
values_.push("1");
|
||||
values_.push("4");
|
||||
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
||||
|
||||
// we should have two values on the stack
|
||||
ASSERT_EQ(2, values_.size());
|
||||
|
||||
// next the equals eval
|
||||
EXPECT_NO_THROW(tequal->evaluate(*pkt4_, values_));
|
||||
ASSERT_EQ(1, values_.size());
|
||||
EXPECT_EQ("false", values_.top());
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,10 @@
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <eval/token.h>
|
||||
#include <eval/eval_log.h>
|
||||
#include <util/encode/hex.h>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
using namespace isc::dhcp;
|
||||
@ -24,6 +28,40 @@ TokenString::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
|
||||
values.push(value_);
|
||||
}
|
||||
|
||||
TokenHexString::TokenHexString(const string& str) : value_("") {
|
||||
// Check string starts "0x" or "0x" and has at least one additional character.
|
||||
if ((str.size() < 3) ||
|
||||
(str[0] != '0') ||
|
||||
((str[1] != 'x') && (str[1] != 'X'))) {
|
||||
return;
|
||||
}
|
||||
string digits = str.substr(2);
|
||||
|
||||
// Transform string of hexadecimal digits into binary format
|
||||
vector<uint8_t> binary;
|
||||
try {
|
||||
// The decodeHex function expects that the string contains an
|
||||
// even number of digits. If we don't meet this requirement,
|
||||
// we have to insert a leading 0.
|
||||
if ((digits.length() % 2) != 0) {
|
||||
digits = digits.insert(0, "0");
|
||||
}
|
||||
util::encode::decodeHex(digits, binary);
|
||||
} catch (...) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert to a string (note that binary.size() cannot be 0)
|
||||
value_.resize(binary.size());
|
||||
memmove(&value_[0], &binary[0], binary.size());
|
||||
}
|
||||
|
||||
void
|
||||
TokenHexString::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
|
||||
// Literals only push, nothing to pop
|
||||
values.push(value_);
|
||||
}
|
||||
|
||||
void
|
||||
TokenOption::evaluate(const Pkt& pkt, ValueStack& values) {
|
||||
OptionPtr opt = pkt.getOption(option_code_);
|
||||
@ -53,3 +91,76 @@ TokenEqual::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
|
||||
else
|
||||
values.push("false");
|
||||
}
|
||||
|
||||
void
|
||||
TokenSubstring::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
|
||||
|
||||
if (values.size() < 3) {
|
||||
isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
|
||||
"3 values for substring operator, got " << values.size());
|
||||
}
|
||||
|
||||
string len_str = values.top();
|
||||
values.pop();
|
||||
string start_str = values.top();
|
||||
values.pop();
|
||||
string string_str = values.top();
|
||||
values.pop();
|
||||
|
||||
// If we have no string to start with we push an empty string and leave
|
||||
if (string_str.empty()) {
|
||||
values.push("");
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the starting position and length from strings to numbers
|
||||
// the length may also be "all" in which case simply make it the
|
||||
// length of the string.
|
||||
// If we have a problem push an empty string and leave
|
||||
int start_pos;
|
||||
int length;
|
||||
try {
|
||||
start_pos = boost::lexical_cast<int>(start_str);
|
||||
if (len_str == "all") {
|
||||
length = string_str.length();
|
||||
} else {
|
||||
length = boost::lexical_cast<int>(len_str);
|
||||
}
|
||||
} catch (const boost::bad_lexical_cast&) {
|
||||
LOG_DEBUG(eval_logger, EVAL_DBG_TRACE,
|
||||
EVAL_SUBSTRING_BAD_PARAM_CONVERSION)
|
||||
.arg(start_str)
|
||||
.arg(len_str);
|
||||
|
||||
values.push("");
|
||||
return;
|
||||
}
|
||||
|
||||
const int string_length = string_str.length();
|
||||
// If the starting postion is outside of the string push an
|
||||
// empty string and leave
|
||||
if ((start_pos < -string_length) || (start_pos >= string_length)) {
|
||||
values.push("");
|
||||
return;
|
||||
}
|
||||
|
||||
// Adjust the values to be something for substr. We first figure out
|
||||
// the starting postion, then update it and the length to get the
|
||||
// characters before or after it depending on the sign of length
|
||||
if (start_pos < 0) {
|
||||
start_pos = string_length + start_pos;
|
||||
}
|
||||
|
||||
if (length < 0) {
|
||||
length = -length;
|
||||
if (length <= start_pos){
|
||||
start_pos -= length;
|
||||
} else {
|
||||
length = start_pos;
|
||||
start_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// and finally get the substring
|
||||
values.push(string_str.substr(start_pos, length));
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ public:
|
||||
/// - option[123] (a token that extracts value of option 123)
|
||||
/// - == (an operator that compares two other tokens)
|
||||
/// - substring(a,b,c) (an operator that takes three arguments: a string,
|
||||
/// first and last character)
|
||||
/// first character and length)
|
||||
class Token {
|
||||
public:
|
||||
|
||||
@ -101,6 +101,31 @@ protected:
|
||||
std::string value_; ///< Constant value
|
||||
};
|
||||
|
||||
/// @brief Token representing a constant string in hexadecimal format
|
||||
///
|
||||
/// This token holds value of a constant string giving in an hexadecimal
|
||||
/// format, for instance 0x666f6f is "foo"
|
||||
class TokenHexString : public Token {
|
||||
public:
|
||||
/// Value is set during token construction.
|
||||
///
|
||||
/// @param str constant string to be represented
|
||||
/// (must be "0x" or "0X" followed by a string of hexadecimal digits
|
||||
/// or decoding will fail)
|
||||
TokenHexString(const std::string& str);
|
||||
|
||||
/// @brief Token evaluation (puts value of the constant string on
|
||||
/// the stack after decoding or an empty string if decoding fails
|
||||
/// (note it should not if the parser is correct)
|
||||
///
|
||||
/// @param pkt (ignored)
|
||||
/// @param values (represented string will be pushed here)
|
||||
void evaluate(const Pkt& pkt, ValueStack& values);
|
||||
|
||||
protected:
|
||||
std::string value_; ///< Constant value
|
||||
};
|
||||
|
||||
/// @brief Token that represents a value of an option
|
||||
///
|
||||
/// This represents a reference to a given option, e.g. in the expression
|
||||
@ -160,10 +185,65 @@ public:
|
||||
/// either "true" or "false". It requires at least two parameters to be
|
||||
/// present on stack.
|
||||
///
|
||||
/// @throw EvalBadStack if there's less than 2 values on stack
|
||||
/// @throw EvalBadStack if there are less than 2 values on stack
|
||||
///
|
||||
/// @brief pkt (unused)
|
||||
/// @brief values - stack of values (2 arguments will be poped, 1 result
|
||||
/// @param pkt (unused)
|
||||
/// @param values - stack of values (2 arguments will be popped, 1 result
|
||||
/// will be pushed)
|
||||
void evaluate(const Pkt& pkt, ValueStack& values);
|
||||
};
|
||||
|
||||
/// @brief Token that represents the substring operator (returns a portion
|
||||
/// of the supplied string)
|
||||
///
|
||||
/// This token represents substring(str, start, len) An operator that takes three
|
||||
/// arguments: a string, the first character and the length.
|
||||
class TokenSubstring : public Token {
|
||||
public:
|
||||
/// @brief Constructor (does nothing)
|
||||
TokenSubstring() {}
|
||||
|
||||
/// @brief Extract a substring from a string
|
||||
///
|
||||
/// Evaluation does not use packet information. It requires at least
|
||||
/// three values to be present on the stack. It will consume the top
|
||||
/// three values on the stack as parameters and push the resulting substring
|
||||
/// onto the stack. From the top it expects the values on the stack as:
|
||||
/// - len
|
||||
/// - start
|
||||
/// - str
|
||||
///
|
||||
/// str is the string to extract a substring from. If it is empty, an empty
|
||||
/// string is pushed onto the value stack.
|
||||
///
|
||||
/// start is the postion from which the code starts extracting the substring.
|
||||
/// 0 is the first character and a negative number starts from the end, with
|
||||
/// -1 being the last character. If the starting point is outside of the
|
||||
/// original string an empty string is pushed onto the value stack.
|
||||
///
|
||||
/// length is the number of characters from the string to extract.
|
||||
/// "all" means all remaining characters from start to the end of string.
|
||||
/// A negative number means to go from start towards the beginning of
|
||||
/// the string, but doesn't include start.
|
||||
/// If length is longer than the remaining portion of string
|
||||
/// then the entire remaining portion is placed on the value stack.
|
||||
///
|
||||
/// The following examples all use the base string "foobar", the first number
|
||||
/// is the starting position and the second is the length. Note that
|
||||
/// a negative length only selects which characters to extract it does not
|
||||
/// indicate an attempt to reverse the string.
|
||||
/// - 0, all => "foobar"
|
||||
/// - 0, 6 => "foobar"
|
||||
/// - 0, 4 => "foob"
|
||||
/// - 2, all => "obar"
|
||||
/// - 2, 6 => "obar"
|
||||
/// - -1, all => "r"
|
||||
/// - -1, -4 => "ooba"
|
||||
///
|
||||
/// @throw EvalBadStack if there are less than 3 values on stack
|
||||
///
|
||||
/// @param pkt (unused)
|
||||
/// @param values - stack of values (3 arguments will be popped, 1 result
|
||||
/// will be pushed)
|
||||
void evaluate(const Pkt& pkt, ValueStack& values);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user