2
0
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:
Francis Dupont 2015-11-06 01:45:20 +01:00
commit 11bc4b3cfc
46 changed files with 1576 additions and 483 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>
}, ...
],

View File

@ -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.

View File

@ -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) ||

View File

@ -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()));
}
}

View File

@ -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));

View File

@ -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\""
" } ]"
" } ]"
"}"

View File

@ -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\""
" } ]"
" } ]"
"}",

View File

@ -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\": ["
" {"

View File

@ -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\""
" } ]"
" } ]"
"}"

View File

@ -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));

View File

@ -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\""
" } ]"
" } ]"
"}"

View File

@ -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) ||

View File

@ -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\""
" } ]"
"}");

View File

@ -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));

View File

@ -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,"

View File

@ -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));

View File

@ -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

View File

@ -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 */

View File

@ -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) {

View File

@ -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_;

View File

@ -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);
}
}

View File

@ -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
View 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
View 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

View File

@ -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:
;
}

View File

@ -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

View File

@ -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

View File

@ -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));

View 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
}

View File

@ -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));

View File

@ -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);

View File

@ -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_;

View File

@ -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

View File

@ -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,"

View File

@ -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
View 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
View 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

View File

@ -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.

View File

@ -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)

View File

@ -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());
}

View File

@ -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));
}

View File

@ -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);
};