mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-03 15:35:17 +00:00
[5374] Final updates
This commit is contained in:
@@ -61,6 +61,13 @@
|
|||||||
</orderedlist>
|
</orderedlist>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
Beginning with 1.4 client classes follow now the insertion order
|
||||||
|
(vs. alphabetical order in previous versions).
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
When determining which options to include in the response the server will examine
|
When determining which options to include in the response the server will examine
|
||||||
the union of options from all of the assigned classes. In the case two or more
|
the union of options from all of the assigned classes. In the case two or more
|
||||||
@@ -223,6 +230,13 @@
|
|||||||
<entry>If the option with given code is present in the
|
<entry>If the option with given code is present in the
|
||||||
packet "true" else "false"</entry>
|
packet "true" else "false"</entry>
|
||||||
</row>
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>Client class membership</entry>
|
||||||
|
<entry>member('foobar')</entry>
|
||||||
|
<entry>'true'</entry>
|
||||||
|
<entry>If the packet belongs to the given client class
|
||||||
|
"true" else "false"</entry>
|
||||||
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>DHCPv4 relay agent sub-option</entry>
|
<entry>DHCPv4 relay agent sub-option</entry>
|
||||||
<entry>relay4[123].hex</entry>
|
<entry>relay4[123].hex</entry>
|
||||||
@@ -472,6 +486,15 @@
|
|||||||
in the incoming packet. It can be used with empty options.
|
in the incoming packet. It can be used with empty options.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>
|
||||||
|
"member('foobar')" checks if the packet belongs to the client
|
||||||
|
class "foobar". To avoid dependency loops the configuration file
|
||||||
|
parser checks if client classes were already defined or are
|
||||||
|
built-in, i.e., beginning by "VENDOR_CLASS_",
|
||||||
|
"AFTER__" (for the to come "after" hook) and
|
||||||
|
"EXTERNAL_".
|
||||||
|
</para></listitem>
|
||||||
|
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
"relay4[code].hex" attempts to extract the value of the sub-option
|
"relay4[code].hex" attempts to extract the value of the sub-option
|
||||||
"code" from the option inserted as the DHCPv4 Relay Agent Information
|
"code" from the option inserted as the DHCPv4 Relay Agent Information
|
||||||
|
@@ -6171,7 +6171,7 @@ const char* UNPARSED_CONFIGS[] = {
|
|||||||
" },\n"
|
" },\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" \"boot-file-name\": \"\",\n"
|
" \"boot-file-name\": \"\",\n"
|
||||||
" \"name\": \"three\",\n"
|
" \"name\": \"two\",\n"
|
||||||
" \"next-server\": \"0.0.0.0\",\n"
|
" \"next-server\": \"0.0.0.0\",\n"
|
||||||
" \"option-data\": [ ],\n"
|
" \"option-data\": [ ],\n"
|
||||||
" \"option-def\": [ ],\n"
|
" \"option-def\": [ ],\n"
|
||||||
@@ -6179,7 +6179,7 @@ const char* UNPARSED_CONFIGS[] = {
|
|||||||
" },\n"
|
" },\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" \"boot-file-name\": \"\",\n"
|
" \"boot-file-name\": \"\",\n"
|
||||||
" \"name\": \"two\",\n"
|
" \"name\": \"three\",\n"
|
||||||
" \"next-server\": \"0.0.0.0\",\n"
|
" \"next-server\": \"0.0.0.0\",\n"
|
||||||
" \"option-data\": [ ],\n"
|
" \"option-data\": [ ],\n"
|
||||||
" \"option-def\": [ ],\n"
|
" \"option-def\": [ ],\n"
|
||||||
|
@@ -992,5 +992,137 @@ TEST_F(ClassifyTest, clientClassesInHostReservations) {
|
|||||||
"2001:db8:1::100"));
|
"2001:db8:1::100"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check classification using membership expressions.
|
||||||
|
TEST_F(ClassifyTest, member) {
|
||||||
|
IfaceMgrTestConfig test_config(true);
|
||||||
|
|
||||||
|
NakedDhcpv6Srv srv(0);
|
||||||
|
|
||||||
|
// The router class matches incoming packets with foo in a host-name
|
||||||
|
// option (code 1234) and sets an ipv6-forwarding option in the response.
|
||||||
|
std::string config = "{ \"interfaces-config\": {"
|
||||||
|
" \"interfaces\": [ \"*\" ] }, "
|
||||||
|
"\"preferred-lifetime\": 3000,"
|
||||||
|
"\"rebind-timer\": 2000, "
|
||||||
|
"\"renew-timer\": 1000, "
|
||||||
|
"\"valid-lifetime\": 4000, "
|
||||||
|
"\"option-def\": [ "
|
||||||
|
"{ \"name\": \"host-name\","
|
||||||
|
" \"code\": 1234,"
|
||||||
|
" \"type\": \"string\" },"
|
||||||
|
"{ \"name\": \"ipv6-forwarding\","
|
||||||
|
" \"code\": 2345,"
|
||||||
|
" \"type\": \"boolean\" }],"
|
||||||
|
"\"subnet6\": [ "
|
||||||
|
"{ \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ], "
|
||||||
|
" \"subnet\": \"2001:db8:1::/48\", "
|
||||||
|
" \"interface\": \"eth1\" } ],"
|
||||||
|
"\"client-classes\": [ "
|
||||||
|
"{ \"name\": \"not-foo\", "
|
||||||
|
" \"test\": \"not (option[host-name].text == 'foo')\""
|
||||||
|
"},"
|
||||||
|
"{ \"name\": \"foo\", "
|
||||||
|
" \"option-data\": ["
|
||||||
|
" { \"name\": \"ipv6-forwarding\", "
|
||||||
|
" \"data\": \"true\" } ], "
|
||||||
|
" \"test\": \"not member('not-foo')\""
|
||||||
|
"},"
|
||||||
|
"{ \"name\": \"bar\", "
|
||||||
|
" \"test\": \"option[host-name].text == 'bar'\""
|
||||||
|
"},"
|
||||||
|
"{ \"name\": \"baz\", "
|
||||||
|
" \"test\": \"option[host-name].text == 'baz'\""
|
||||||
|
"},"
|
||||||
|
"{ \"name\": \"barz\", "
|
||||||
|
" \"option-data\": ["
|
||||||
|
" { \"name\": \"ipv6-forwarding\", "
|
||||||
|
" \"data\": \"false\" } ], "
|
||||||
|
" \"test\": \"member('bar') or member('baz')\" } ] }";
|
||||||
|
|
||||||
|
ASSERT_NO_THROW(configure(config));
|
||||||
|
|
||||||
|
// Create packets with enough to select the subnet
|
||||||
|
OptionPtr clientid = generateClientId();
|
||||||
|
Pkt6Ptr query1(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||||
|
query1->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||||
|
query1->addOption(clientid);
|
||||||
|
query1->setIface("eth1");
|
||||||
|
query1->addOption(generateIA(D6O_IA_NA, 123, 1500, 3000));
|
||||||
|
Pkt6Ptr query2(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||||
|
query2->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||||
|
query2->addOption(clientid);
|
||||||
|
query2->setIface("eth1");
|
||||||
|
query2->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
|
||||||
|
Pkt6Ptr query3(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||||
|
query3->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||||
|
query3->addOption(clientid);
|
||||||
|
query3->setIface("eth1");
|
||||||
|
query3->addOption(generateIA(D6O_IA_NA, 345, 1500, 3000));
|
||||||
|
|
||||||
|
// Create and add an ORO option to queries
|
||||||
|
OptionUint16ArrayPtr oro(new OptionUint16Array(Option::V6, D6O_ORO));
|
||||||
|
ASSERT_TRUE(oro);
|
||||||
|
oro->addValue(2345);
|
||||||
|
query1->addOption(oro);
|
||||||
|
query2->addOption(oro);
|
||||||
|
query3->addOption(oro);
|
||||||
|
|
||||||
|
// Create and add a host-name option to the first and last queries
|
||||||
|
OptionStringPtr hostname1(new OptionString(Option::V6, 1234, "foo"));
|
||||||
|
ASSERT_TRUE(hostname1);
|
||||||
|
query1->addOption(hostname1);
|
||||||
|
OptionStringPtr hostname3(new OptionString(Option::V6, 1234, "baz"));
|
||||||
|
ASSERT_TRUE(hostname3);
|
||||||
|
query3->addOption(hostname3);
|
||||||
|
|
||||||
|
// Classify packets
|
||||||
|
srv.classifyPacket(query1);
|
||||||
|
srv.classifyPacket(query2);
|
||||||
|
srv.classifyPacket(query3);
|
||||||
|
|
||||||
|
// Check classes
|
||||||
|
EXPECT_FALSE(query1->inClass("not-foo"));
|
||||||
|
EXPECT_TRUE(query1->inClass("foo"));
|
||||||
|
EXPECT_FALSE(query1->inClass("bar"));
|
||||||
|
EXPECT_FALSE(query1->inClass("baz"));
|
||||||
|
EXPECT_FALSE(query1->inClass("barz"));
|
||||||
|
|
||||||
|
EXPECT_TRUE(query2->inClass("not-foo"));
|
||||||
|
EXPECT_FALSE(query2->inClass("foo"));
|
||||||
|
EXPECT_FALSE(query2->inClass("bar"));
|
||||||
|
EXPECT_FALSE(query2->inClass("baz"));
|
||||||
|
EXPECT_FALSE(query2->inClass("barz"));
|
||||||
|
|
||||||
|
EXPECT_TRUE(query3->inClass("not-foo"));
|
||||||
|
EXPECT_FALSE(query3->inClass("foo"));
|
||||||
|
EXPECT_FALSE(query3->inClass("bar"));
|
||||||
|
EXPECT_TRUE(query3->inClass("baz"));
|
||||||
|
EXPECT_TRUE(query3->inClass("barz"));
|
||||||
|
|
||||||
|
// Process queries
|
||||||
|
Pkt6Ptr response1 = srv.processSolicit(query1);
|
||||||
|
Pkt6Ptr response2 = srv.processSolicit(query2);
|
||||||
|
Pkt6Ptr response3 = srv.processSolicit(query3);
|
||||||
|
|
||||||
|
// Classification processing should add an ip-forwarding option
|
||||||
|
OptionPtr opt1 = response1->getOption(2345);
|
||||||
|
EXPECT_TRUE(opt1);
|
||||||
|
OptionCustomPtr ipf1 =
|
||||||
|
boost::dynamic_pointer_cast<OptionCustom>(opt1);
|
||||||
|
ASSERT_TRUE(ipf1);
|
||||||
|
EXPECT_TRUE(ipf1->readBoolean());
|
||||||
|
|
||||||
|
// But not the second query which was not classified
|
||||||
|
OptionPtr opt2 = response2->getOption(2345);
|
||||||
|
EXPECT_FALSE(opt2);
|
||||||
|
|
||||||
|
// The third has the option but with another value
|
||||||
|
OptionPtr opt3 = response3->getOption(2345);
|
||||||
|
EXPECT_TRUE(opt3);
|
||||||
|
OptionCustomPtr ipf3 =
|
||||||
|
boost::dynamic_pointer_cast<OptionCustom>(opt3);
|
||||||
|
ASSERT_TRUE(ipf3);
|
||||||
|
EXPECT_FALSE(ipf3->readBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
} // end of anonymous namespace
|
} // end of anonymous namespace
|
||||||
|
@@ -5467,11 +5467,11 @@ const char* UNPARSED_CONFIGS[] = {
|
|||||||
" \"option-data\": [ ]\n"
|
" \"option-data\": [ ]\n"
|
||||||
" },\n"
|
" },\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" \"name\": \"three\",\n"
|
" \"name\": \"two\",\n"
|
||||||
" \"option-data\": [ ]\n"
|
" \"option-data\": [ ]\n"
|
||||||
" },\n"
|
" },\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" \"name\": \"two\",\n"
|
" \"name\": \"three\",\n"
|
||||||
" \"option-data\": [ ]\n"
|
" \"option-data\": [ ]\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
" ],\n"
|
" ],\n"
|
||||||
|
Reference in New Issue
Block a user