]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5351] Checkpoint: todo servers, doc, host DB -- adding control-socket
authorFrancis Dupont <fdupont@isc.org>
Sat, 2 Dec 2017 15:28:34 +0000 (16:28 +0100)
committerFrancis Dupont <fdupont@isc.org>
Sat, 2 Dec 2017 15:28:34 +0000 (16:28 +0100)
src/bin/dhcp4/dhcp4_lexer.ll
src/bin/dhcp4/dhcp4_parser.yy
src/bin/dhcp4/json_config_parser.cc
src/bin/dhcp6/dhcp6_lexer.ll
src/bin/dhcp6/dhcp6_parser.yy
src/bin/dhcp6/json_config_parser.cc
src/lib/dhcpsrv/host.cc
src/lib/dhcpsrv/parsers/host_reservation_parser.cc
src/lib/dhcpsrv/tests/host_unittest.cc

index 3f9027a4d6b7484e96bc9c109bc1f0011668313f..65184f61d444372372cb344cd733175ea08c0a57 100644 (file)
@@ -589,6 +589,7 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     case isc::dhcp::Parser4Context::OPTION_DATA:
     case isc::dhcp::Parser4Context::RESERVATIONS:
     case isc::dhcp::Parser4Context::CLIENT_CLASSES:
+    case isc::dhcp::Parser4Context::CONTROL_SOCKET:
     case isc::dhcp::Parser4Context::LOGGERS:
     case isc::dhcp::Parser4Context::DHCP_DDNS:
         return isc::dhcp::Dhcp4Parser::make_USER_CONTEXT(driver.loc_);
@@ -610,6 +611,7 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     case isc::dhcp::Parser4Context::OPTION_DATA:
     case isc::dhcp::Parser4Context::RESERVATIONS:
     case isc::dhcp::Parser4Context::CLIENT_CLASSES:
+    case isc::dhcp::Parser4Context::CONTROL_SOCKET:
     case isc::dhcp::Parser4Context::LOGGERS:
     case isc::dhcp::Parser4Context::DHCP_DDNS:
         return isc::dhcp::Dhcp4Parser::make_COMMENT(driver.loc_);
index e31f1570cf4802a8a7ceffa34257e231fcfc2da5..d56637ec9dbbfe3092ec052af9ce4714717ac10a 100644 (file)
@@ -1633,6 +1633,9 @@ control_socket_params: control_socket_param
 
 control_socket_param: control_socket_type
                     | control_socket_name
+                    | user_context
+                    | comment
+                    | unknown_map_entry
                     ;
 
 control_socket_type: SOCKET_TYPE {
index d0cf070db3d7d5e18dddc291bcedf1c19969a35e..4c8417ef5e833da0a52007dcb4d73ee7f6895767 100644 (file)
@@ -253,7 +253,7 @@ void configureCommandChannel() {
     // If the previous or new socket configuration doesn't exist or
     // the new configuration differs from the old configuration we
     // close the existing socket and open a new socket as appropriate.
-    // Note that closing an existing socket means the clien will not
+    // Note that closing an existing socket means the client will not
     // receive the configuration result.
     if (!sock_cfg || !current_sock_cfg || sock_changed) {
         // Close the existing socket (if any).
index c83ae0328513437f4492485f23e1d65374e7cd0b..38de3af809d66c8a2da3ac7ab67001932c594a38 100644 (file)
@@ -818,6 +818,7 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     case isc::dhcp::Parser6Context::OPTION_DATA:
     case isc::dhcp::Parser6Context::CLIENT_CLASSES:
     case isc::dhcp::Parser6Context::SERVER_ID:
+    case isc::dhcp::Parser6Context::CONTROL_SOCKET:
     case isc::dhcp::Parser6Context::POOLS:
     case isc::dhcp::Parser6Context::PD_POOLS:
     case isc::dhcp::Parser6Context::RESERVATIONS:
@@ -841,6 +842,7 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     case isc::dhcp::Parser6Context::OPTION_DATA:
     case isc::dhcp::Parser6Context::CLIENT_CLASSES:
     case isc::dhcp::Parser6Context::SERVER_ID:
+    case isc::dhcp::Parser6Context::CONTROL_SOCKET:
     case isc::dhcp::Parser6Context::POOLS:
     case isc::dhcp::Parser6Context::PD_POOLS:
     case isc::dhcp::Parser6Context::RESERVATIONS:
index 3b8bef3e2a7c0a959664c55f280b11c9558b4d10..10eca1db5ad470f2fe4e7470445a55e3a4f93348 100644 (file)
@@ -1716,6 +1716,9 @@ control_socket_params: control_socket_param
 
 control_socket_param: socket_type
                     | socket_name
+                    | user_context
+                    | comment
+                    | unknown_map_entry
                     ;
 
 socket_type: SOCKET_TYPE {
index d74dab56cf7b03e72939cca8bd60ad2d1d6a173a..bab6ebe21d4ee01c424879d54dcce96d14f29086 100644 (file)
@@ -350,7 +350,7 @@ void configureCommandChannel() {
     // If the previous or new socket configuration doesn't exist or
     // the new configuration differs from the old configuration we
     // close the existing socket and open a new socket as appropriate.
-    // Note that closing an existing socket means the clien will not
+    // Note that closing an existing socket means the client will not
     // receive the configuration result.
     if (!sock_cfg || !current_sock_cfg || sock_changed) {
         // Close the existing socket (if any).
index 0df727130f6feaf624c174200ac56dd963533d2f..4b644977cda778e71163186782514f5544cf2820 100644 (file)
@@ -468,6 +468,8 @@ ElementPtr
 Host::toElement6() const {
     // Prepare the map
     ElementPtr map = Element::createMap();
+    // Set the user context
+    contextToElement(map);
     // Set the identifier
     Host::IdentifierType id_type = getIdentifierType();
     if (id_type == Host::IDENT_HWADDR) {
index d066c1f250e47148128b6ff16ae6d0a1d806ac7f..3ec3fd5cca0d2988210ac6dd172e00b5c55ce0cc 100644 (file)
@@ -54,6 +54,7 @@ getSupportedParams4(const bool identifiers_only = false) {
         params_set.insert("server-hostname");
         params_set.insert("boot-file-name");
         params_set.insert("client-classes");
+        params_set.insert("user-context");
     }
     return (identifiers_only ? identifiers_set : params_set);
 }
@@ -87,6 +88,7 @@ getSupportedParams6(const bool identifiers_only = false) {
         params_set.insert("prefixes");
         params_set.insert("option-data");
         params_set.insert("client-classes");
+        params_set.insert("user-context");
     }
     return (identifiers_only ? identifiers_set : params_set);
 }
@@ -108,6 +110,7 @@ HostReservationParser::parseInternal(const SubnetID&,
     std::string identifier;
     std::string identifier_name;
     std::string hostname;
+    ConstElementPtr user_context;
     HostPtr host;
 
     try {
@@ -131,7 +134,8 @@ HostReservationParser::parseInternal(const SubnetID&,
 
             } else if (element.first == "hostname") {
                 hostname = element.second->stringValue();
-
+            } else if (element.first == "user-context") {
+                user_context = element.second;
             }
         }
 
@@ -157,6 +161,10 @@ HostReservationParser::parseInternal(const SubnetID&,
         host.reset(new Host(identifier, identifier_name, SubnetID(0),
                              SubnetID(0), IOAddress("0.0.0.0"), hostname));
 
+        // Add user context
+        if (user_context) {
+            host->setContext(user_context);
+        }
     } catch (const std::exception& ex) {
         // Append line number where the error occurred.
         isc_throw(DhcpConfigError, ex.what() << " ("
index fad37178ec10c87901557a0e8b7023a91d5e7c63..e5e219e1426f599600e3a5c4336bebb62651236f 100644 (file)
@@ -18,6 +18,7 @@
 using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::asiolink;
+using namespace isc::data;
 
 namespace {
 
@@ -214,6 +215,7 @@ TEST_F(HostTest, createFromHWAddrString) {
     EXPECT_EQ("192.0.0.2", host->getNextServer().toText());
     EXPECT_EQ("server-hostname.example.org", host->getServerHostname());
     EXPECT_EQ("bootfile.efi", host->getBootFileName());
+    EXPECT_FALSE(host->getContext());
 
     // Use invalid identifier name
     EXPECT_THROW(Host("01:02:03:04:05:06", "bogus", SubnetID(1), SubnetID(2),
@@ -248,6 +250,7 @@ TEST_F(HostTest, createFromDUIDString) {
     EXPECT_EQ(20, host->getIPv6SubnetID());
     EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
     EXPECT_EQ("me.example.org", host->getHostname());
+    EXPECT_FALSE(host->getContext());
 
     // Use invalid DUID.
     EXPECT_THROW(Host("bogus", "duid", SubnetID(1), SubnetID(2),
@@ -294,6 +297,7 @@ TEST_F(HostTest, createFromHWAddrBinary) {
     EXPECT_EQ("192.0.0.2", host->getNextServer().toText());
     EXPECT_EQ("server-hostname.example.org", host->getServerHostname());
     EXPECT_EQ("bootfile.efi", host->getBootFileName());
+    EXPECT_FALSE(host->getContext());
 }
 
 // This test verifies that it is possible to create a Host object using
@@ -322,6 +326,7 @@ TEST_F(HostTest, createFromDuidBinary) {
     EXPECT_EQ(20, host->getIPv6SubnetID());
     EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
     EXPECT_EQ("me.example.org", host->getHostname());
+    EXPECT_FALSE(host->getContext());
 }
 
 // This test verifies that it is possible create Host instance using all
@@ -350,6 +355,7 @@ TEST_F(HostTest, createFromIdentifierBinary) {
         EXPECT_EQ(20, host->getIPv6SubnetID());
         EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
         EXPECT_EQ("me.example.org", host->getHostname());
+        EXPECT_FALSE(host->getContext());
     }
 }
 
@@ -395,6 +401,7 @@ TEST_F(HostTest, createFromIdentifierHex) {
         EXPECT_EQ(20, host->getIPv6SubnetID());
         EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
         EXPECT_EQ("me.example.org", host->getHostname());
+        EXPECT_FALSE(host->getContext());
     }
 }
 
@@ -439,6 +446,7 @@ TEST_F(HostTest, createFromIdentifierString) {
         EXPECT_EQ(20, host->getIPv6SubnetID());
         EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
         EXPECT_EQ("me.example.org", host->getHostname());
+        EXPECT_FALSE(host->getContext());
     }
 }
 
@@ -493,6 +501,7 @@ TEST_F(HostTest, setIdentifierHex) {
         EXPECT_EQ(20, host->getIPv6SubnetID());
         EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
         EXPECT_EQ("me.example.org", host->getHostname());
+        EXPECT_FALSE(host->getContext());
 
         // Now use another identifier.
         type = static_cast<Host::IdentifierType>(i);
@@ -525,6 +534,7 @@ TEST_F(HostTest, setIdentifierHex) {
         EXPECT_EQ(20, host->getIPv6SubnetID());
         EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
         EXPECT_EQ("me.example.org", host->getHostname());
+        EXPECT_FALSE(host->getContext());
     }
 }
 
@@ -563,6 +573,7 @@ TEST_F(HostTest, setIdentifierBinary) {
         EXPECT_EQ(20, host->getIPv6SubnetID());
         EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
         EXPECT_EQ("me.example.org", host->getHostname());
+        EXPECT_FALSE(host->getContext());
 
         type = static_cast<Host::IdentifierType>(i);
         // Create identifier of variable length and fill with random values.
@@ -582,6 +593,7 @@ TEST_F(HostTest, setIdentifierBinary) {
         EXPECT_EQ(20, host->getIPv6SubnetID());
         EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
         EXPECT_EQ("me.example.org", host->getHostname());
+        EXPECT_FALSE(host->getContext());
     }
 }
 
@@ -656,6 +668,7 @@ TEST_F(HostTest, setValues) {
     ASSERT_EQ(2, host->getIPv6SubnetID());
     ASSERT_EQ("192.0.2.3", host->getIPv4Reservation().toText());
     ASSERT_EQ("some-host.example.org", host->getHostname());
+    ASSERT_FALSE(host->getContext());
 
     host->setIPv4SubnetID(SubnetID(123));
     host->setIPv6SubnetID(SubnetID(234));
@@ -664,6 +677,8 @@ TEST_F(HostTest, setValues) {
     host->setNextServer(IOAddress("192.0.2.2"));
     host->setServerHostname("server-hostname.example.org");
     host->setBootFileName("bootfile.efi");
+    std::string user_context = "{ \"foo\": \"bar\" }";
+    host->setContext(Element::fromJSON(user_context));
 
     EXPECT_EQ(123, host->getIPv4SubnetID());
     EXPECT_EQ(234, host->getIPv6SubnetID());
@@ -672,6 +687,8 @@ TEST_F(HostTest, setValues) {
     EXPECT_EQ("192.0.2.2", host->getNextServer().toText());
     EXPECT_EQ("server-hostname.example.org", host->getServerHostname());
     EXPECT_EQ("bootfile.efi", host->getBootFileName());
+    ASSERT_TRUE(host->getContext());
+    EXPECT_EQ(user_context, host->getContext()->str());
 
     // Remove IPv4 reservation.
     host->removeIPv4Reservation();
@@ -943,6 +960,10 @@ TEST_F(HostTest, toText) {
                                        IOAddress("2001:db8:1::1")));
     );
 
+    // Add invisble user context
+    std::string user_context = "{ \"foo\": \"bar\" }";
+    host->setContext(Element::fromJSON(user_context));
+
     // Make sure that the output is correct,
     EXPECT_EQ("hwaddr=010203040506 ipv4_subnet_id=1 ipv6_subnet_id=2"
               " hostname=myhost.example.com"
@@ -1010,6 +1031,165 @@ TEST_F(HostTest, toText) {
               host->toText());
 }
 
+// This test checks that Host object is correctly unparsed,
+TEST_F(HostTest, unparse) {
+    boost::scoped_ptr<Host> host;
+    ASSERT_NO_THROW(host.reset(new Host("01:02:03:04:05:06", "hw-address",
+                                        SubnetID(1), SubnetID(2),
+                                        IOAddress("192.0.2.3"),
+                                        "myhost.example.com")));
+
+    // Add 4 reservations: 2 for NAs, 2 for PDs.
+    ASSERT_NO_THROW(
+        host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
+                                       IOAddress("2001:db8:1::cafe")));
+        host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
+                                       IOAddress("2001:db8:1:1::"), 64));
+        host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
+                                       IOAddress("2001:db8:1:2::"), 64));
+        host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
+                                       IOAddress("2001:db8:1::1")));
+    );
+
+    // Add user context
+    std::string user_context = "{ \"comment\": \"a host reservation\" }";
+    host->setContext(Element::fromJSON(user_context));
+
+    // Make sure that the output is correct,
+    EXPECT_EQ("{ "
+              "\"boot-file-name\": \"\", "
+              "\"client-classes\": [  ], "
+              "\"comment\": \"a host reservation\", "
+              "\"hostname\": \"myhost.example.com\", "
+              "\"hw-address\": \"01:02:03:04:05:06\", "
+              "\"ip-address\": \"192.0.2.3\", "
+              "\"next-server\": \"0.0.0.0\", "
+              "\"option-data\": [  ], "
+              "\"server-hostname\": \"\" "
+              "}",
+              host->toElement4()->str());
+
+    EXPECT_EQ("{ "
+              "\"client-classes\": [  ], "
+              "\"comment\": \"a host reservation\", "
+              "\"hostname\": \"myhost.example.com\", "
+              "\"hw-address\": \"01:02:03:04:05:06\", "
+              "\"ip-addresses\": [ \"2001:db8:1::cafe\", \"2001:db8:1::1\" ], "
+              "\"option-data\": [  ], "
+              "\"prefixes\": [ \"2001:db8:1:1::/64\", \"2001:db8:1:2::/64\" ] "
+              "}",
+              host->toElement6()->str());
+
+    // Reset some of the data and make sure that the output is affected.
+    host->setHostname("");
+    host->removeIPv4Reservation();
+    host->setIPv4SubnetID(0);
+
+    EXPECT_EQ("{ "
+              "\"boot-file-name\": \"\", "
+              "\"client-classes\": [  ], "
+              "\"comment\": \"a host reservation\", "
+              "\"hostname\": \"\", "
+              "\"hw-address\": \"01:02:03:04:05:06\", "
+              "\"ip-address\": \"0.0.0.0\", "
+              "\"next-server\": \"0.0.0.0\", "
+              "\"option-data\": [  ], "
+              "\"server-hostname\": \"\" "
+              "}",
+              host->toElement4()->str());
+
+    EXPECT_EQ("{ "
+              "\"client-classes\": [  ], "
+              "\"comment\": \"a host reservation\", "
+              "\"hostname\": \"\", "
+              "\"hw-address\": \"01:02:03:04:05:06\", "
+              "\"ip-addresses\": [ \"2001:db8:1::cafe\", \"2001:db8:1::1\" ], "
+              "\"option-data\": [  ], "
+              "\"prefixes\": [ \"2001:db8:1:1::/64\", \"2001:db8:1:2::/64\" ] "
+              "}",
+              host->toElement6()->str());
+
+    // Create host identified by DUID, instead of HWADDR, with a very
+    // basic configuration.
+    ASSERT_NO_THROW(host.reset(new Host("11:12:13:14:15", "duid",
+                                        SubnetID(0), SubnetID(0),
+                                        IOAddress::IPV4_ZERO_ADDRESS(),
+                                        "myhost")));
+
+    EXPECT_EQ("{ "
+              "\"boot-file-name\": \"\", "
+              "\"client-classes\": [  ], "
+              "\"duid\": \"11:12:13:14:15\", "
+              "\"hostname\": \"myhost\", "
+              "\"ip-address\": \"0.0.0.0\", "
+              "\"next-server\": \"0.0.0.0\", "
+              "\"option-data\": [  ], "
+              "\"server-hostname\": \"\" "
+              "}",
+              host->toElement4()->str());
+
+    EXPECT_EQ("{ "
+              "\"client-classes\": [  ], "
+              "\"duid\": \"11:12:13:14:15\", "
+              "\"hostname\": \"myhost\", "
+              "\"ip-addresses\": [  ], "
+              "\"option-data\": [  ], "
+              "\"prefixes\": [  ] "
+              "}",
+              host->toElement6()->str());
+
+    // Add some classes.
+    host->addClientClass4("modem");
+    host->addClientClass4("router");
+
+    EXPECT_EQ("{ "
+              "\"boot-file-name\": \"\", "
+              "\"client-classes\": [ \"modem\", \"router\" ], "
+              "\"duid\": \"11:12:13:14:15\", "
+              "\"hostname\": \"myhost\", "
+              "\"ip-address\": \"0.0.0.0\", "
+              "\"next-server\": \"0.0.0.0\", "
+              "\"option-data\": [  ], "
+              "\"server-hostname\": \"\" "
+              "}",
+              host->toElement4()->str());
+
+    EXPECT_EQ("{ "
+              "\"client-classes\": [  ], "
+              "\"duid\": \"11:12:13:14:15\", "
+              "\"hostname\": \"myhost\", "
+              "\"ip-addresses\": [  ], "
+              "\"option-data\": [  ], "
+              "\"prefixes\": [  ] "
+              "}",
+              host->toElement6()->str());
+
+    host->addClientClass6("hub");
+    host->addClientClass6("device");
+
+    EXPECT_EQ("{ "
+              "\"boot-file-name\": \"\", "
+              "\"client-classes\": [ \"modem\", \"router\" ], "
+              "\"duid\": \"11:12:13:14:15\", "
+              "\"hostname\": \"myhost\", "
+              "\"ip-address\": \"0.0.0.0\", "
+              "\"next-server\": \"0.0.0.0\", "
+              "\"option-data\": [  ], "
+              "\"server-hostname\": \"\" "
+              "}",
+              host->toElement4()->str());
+
+    EXPECT_EQ("{ "
+              "\"client-classes\": [ \"device\", \"hub\" ], "
+              "\"duid\": \"11:12:13:14:15\", "
+              "\"hostname\": \"myhost\", "
+              "\"ip-addresses\": [  ], "
+              "\"option-data\": [  ], "
+              "\"prefixes\": [  ] "
+              "}",
+              host->toElement6()->str());
+}
+
 // Test verifies if the host can store HostId properly.
 TEST_F(HostTest, hostId) {
     boost::scoped_ptr<Host> host;