1 // Copyright (C) 2011-2021 Internet Systems Consortium, Inc. ("ISC") 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, v. 2.0. If a copy of the MPL was not distributed with this 5 // file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 7 #ifndef DHCPV6_SRV_H 8 #define DHCPV6_SRV_H 9 10 #include <asiolink/io_service.h> 11 #include <dhcp/dhcp6.h> 12 #include <dhcp/duid.h> 13 #include <dhcp/option.h> 14 #include <dhcp/option_string.h> 15 #include <dhcp/option6_client_fqdn.h> 16 #include <dhcp/option6_ia.h> 17 #include <dhcp/option_custom.h> 18 #include <dhcp/option_definition.h> 19 #include <dhcp_ddns/ncr_msg.h> 20 #include <dhcp/pkt6.h> 21 #include <dhcpsrv/alloc_engine.h> 22 #include <dhcpsrv/callout_handle_store.h> 23 #include <dhcpsrv/cb_ctl_dhcp6.h> 24 #include <dhcpsrv/cfg_option.h> 25 #include <dhcpsrv/d2_client_mgr.h> 26 #include <dhcpsrv/network_state.h> 27 #include <dhcpsrv/subnet.h> 28 #include <hooks/callout_handle.h> 29 #include <process/daemon.h> 30 31 #include <functional> 32 #include <iostream> 33 #include <queue> 34 35 // Undefine the macro OPTIONAL which is defined in some operating 36 // systems but conflicts with a member of the RequirementLevel enum in 37 // the server class. 38 39 #ifdef OPTIONAL 40 #undef OPTIONAL 41 #endif 42 43 namespace isc { 44 namespace dhcp { 45 46 /// @brief This exception is thrown when DHCP server hits the error which should 47 /// result in discarding the message being processed. 48 class DHCPv6DiscardMessageError : public Exception { 49 public: DHCPv6DiscardMessageError(const char * file,size_t line,const char * what)50 DHCPv6DiscardMessageError(const char* file, size_t line, const char* what) : 51 isc::Exception(file, line, what) { }; 52 }; 53 54 /// @brief DHCPv6 server service. 55 /// 56 /// This singleton class represents DHCPv6 server. It contains all 57 /// top-level methods and routines necessary for server operation. 58 /// In particular, it instantiates IfaceMgr, loads or generates DUID 59 /// that is going to be used as server-identifier, receives incoming 60 /// packets, processes them, manages leases assignment and generates 61 /// appropriate responses. 62 /// 63 /// This class does not support any controlling mechanisms directly. 64 /// See the derived \ref ControlledDhcpv6Srv class for support for 65 /// command and configuration updates over msgq. 66 class Dhcpv6Srv : public process::Daemon { 67 private: 68 69 /// @brief Pointer to IO service used by the server. 70 asiolink::IOServicePtr io_service_; 71 72 public: 73 /// @brief defines if certain option may, must or must not appear 74 typedef enum { 75 FORBIDDEN, 76 MANDATORY, 77 OPTIONAL 78 } RequirementLevel; 79 80 /// @brief Minimum length of a MAC address to be used in DUID generation. 81 static const size_t MIN_MAC_LEN = 6; 82 83 /// @brief Default constructor. 84 /// 85 /// Instantiates necessary services, required to run DHCPv6 server. 86 /// In particular, creates IfaceMgr that will be responsible for 87 /// network interaction. Will instantiate lease manager, and load 88 /// old or create new DUID. It is possible to specify alternate 89 /// port on which DHCPv6 server will listen on and alternate port 90 /// where DHCPv6 server sends all responses to. Those are mostly useful 91 /// for testing purposes. 92 /// 93 /// @param server_port specifies port number to listen on 94 /// @param client_port specifies port number to send to 95 Dhcpv6Srv(uint16_t server_port = DHCP6_SERVER_PORT, 96 uint16_t client_port = 0); 97 98 /// @brief Destructor. Used during DHCPv6 service shutdown. 99 virtual ~Dhcpv6Srv(); 100 101 /// @brief Checks if the server is running in unit test mode. 102 /// 103 /// @return true if the server is running in unit test mode, 104 /// false otherwise. inTestMode()105 bool inTestMode() const { 106 return (server_port_ == 0); 107 } 108 109 /// @brief Returns pointer to the IO service used by the server. getIOService()110 asiolink::IOServicePtr& getIOService() { 111 return (io_service_); 112 } 113 114 /// @brief Returns pointer to the network state used by the server. getNetworkState()115 NetworkStatePtr& getNetworkState() { 116 return (network_state_); 117 } 118 119 /// @brief Returns an object which controls access to the configuration 120 /// backends. 121 /// 122 /// @return Pointer to the instance of the object which controls 123 /// access to the configuration backends. getCBControl()124 CBControlDHCPv6Ptr getCBControl() const { 125 return (cb_control_); 126 } 127 128 /// @brief returns Kea version on stdout and exit. 129 /// redeclaration/redefinition. @ref isc::process::Daemon::getVersion() 130 static std::string getVersion(bool extended); 131 132 /// @brief Returns server-identifier option. 133 /// 134 /// @return server-id option getServerID()135 OptionPtr getServerID() { return serverid_; } 136 137 /// @brief Main server processing loop. 138 /// 139 /// Main server processing loop. Call the processing step routine 140 /// until shut down. 141 /// 142 /// @return The value returned by @c Daemon::getExitValue(). 143 int run(); 144 145 /// @brief Main server processing step. 146 /// 147 /// Main server processing step. Receives one incoming packet, calls 148 /// the processing packet routing and (if necessary) transmits 149 /// a response. 150 void run_one(); 151 152 /// @brief Process a single incoming DHCPv6 packet and sends the response. 153 /// 154 /// It verifies correctness of the passed packet, calls per-type processXXX 155 /// methods, generates appropriate answer, sends the answer to the client. 156 /// 157 /// @param query A pointer to the packet to be processed. 158 void processPacketAndSendResponse(Pkt6Ptr& query); 159 160 /// @brief Process a single incoming DHCPv6 packet and sends the response. 161 /// 162 /// It verifies correctness of the passed packet, calls per-type processXXX 163 /// methods, generates appropriate answer, sends the answer to the client. 164 /// 165 /// @param query A pointer to the packet to be processed. 166 void processPacketAndSendResponseNoThrow(Pkt6Ptr& query); 167 168 /// @brief Process an unparked DHCPv6 packet and sends the response. 169 /// 170 /// @param callout_handle pointer to the callout handle. 171 /// @param query A pointer to the packet to be processed. 172 /// @param rsp A pointer to the response. 173 void sendResponseNoThrow(hooks::CalloutHandlePtr& callout_handle, 174 Pkt6Ptr& query, Pkt6Ptr& rsp); 175 176 /// @brief Process a single incoming DHCPv6 packet. 177 /// 178 /// It verifies correctness of the passed packet, calls per-type processXXX 179 /// methods, generates appropriate answer. 180 /// 181 /// @param query A pointer to the packet to be processed. 182 /// @param rsp A pointer to the response. 183 void processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp); 184 185 /// @brief Process a single incoming DHCPv6 query. 186 /// 187 /// It calls per-type processXXX methods, generates appropriate answer. 188 /// 189 /// @param query A pointer to the packet to be processed. 190 /// @param rsp A pointer to the response. 191 void processDhcp6Query(Pkt6Ptr& query, Pkt6Ptr& rsp); 192 193 /// @brief Process a single incoming DHCPv6 query. 194 /// 195 /// It calls per-type processXXX methods, generates appropriate answer, 196 /// sends the answer to the client. 197 /// 198 /// @param query A pointer to the packet to be processed. 199 /// @param rsp A pointer to the response. 200 void processDhcp6QueryAndSendResponse(Pkt6Ptr& query, Pkt6Ptr& rsp); 201 202 /// @brief Instructs the server to shut down. 203 void shutdown() override; 204 205 /// 206 /// @name Public accessors returning values required to (re)open sockets. 207 /// 208 //@{ 209 /// 210 /// @brief Get UDP port on which server should listen. 211 /// 212 /// Typically, server listens on UDP port number 547. Other ports are used 213 /// for testing purposes only. 214 /// 215 /// @return UDP port on which server should listen. getServerPort()216 uint16_t getServerPort() const { 217 return (server_port_); 218 } 219 //@} 220 221 /// @brief Starts DHCP_DDNS client IO if DDNS updates are enabled. 222 /// 223 /// If updates are enabled, it instructs the D2ClientMgr singleton to 224 /// enter send mode. If D2ClientMgr encounters errors it may throw 225 /// D2ClientError. This method does not catch exceptions. 226 void startD2(); 227 228 /// @brief Stops DHCP_DDNS client IO if DDNS updates are enabled. 229 /// 230 /// If updates are enabled, it instructs the D2ClientMgr singleton to 231 /// leave send mode. If D2ClientMgr encounters errors it may throw 232 /// D2ClientError. This method does not catch exceptions. 233 void stopD2(); 234 235 /// @brief Implements the error handler for DHCP_DDNS IO errors 236 /// 237 /// Invoked when a NameChangeRequest send to kea-dhcp-ddns completes with 238 /// a failed status. These are communications errors, not data related 239 /// failures. 240 /// 241 /// This method logs the failure and then suspends all further updates. 242 /// Updating can only be restored by reconfiguration or restarting the 243 /// server. There is currently no retry logic so the first IO error that 244 /// occurs will suspend updates. 245 /// @todo We may wish to make this more robust or sophisticated. 246 /// 247 /// @param result Result code of the send operation. 248 /// @param ncr NameChangeRequest which failed to send. 249 virtual void d2ClientErrorHandler(const dhcp_ddns:: 250 NameChangeSender::Result result, 251 dhcp_ddns::NameChangeRequestPtr& ncr); 252 253 /// @brief Discards parked packets 254 /// Clears the packet parking lots of all packets. 255 /// Called during reconfigure and shutdown. 256 void discardPackets(); 257 258 protected: 259 260 /// @brief This function sets statistics related to DHCPv6 packets processing 261 /// to their initial values. 262 /// 263 /// All of the statistics observed by the DHCPv6 server and with the names 264 /// like "pkt6-" are reset to 0. This function must be invoked in the class 265 /// constructor. 266 void setPacketStatisticsDefaults(); 267 268 /// @brief Compare received server id with our server id 269 /// 270 /// Checks if the server id carried in a query from a client matches 271 /// server identifier being used by the server. 272 /// 273 /// @param pkt DHCPv6 packet carrying server identifier to be checked. 274 /// @return true if server id carried in the query matches server id 275 /// used by the server; false otherwise. 276 bool testServerID(const Pkt6Ptr& pkt); 277 278 /// @brief Check if the message can be sent to unicast. 279 /// 280 /// This function checks if the received message conforms to the section 16 281 /// of RFC 8415 which says that: "A server MUST discard any Solicit, Confirm, 282 /// Rebind or Information-request messages it receives with a Layer 3 unicast 283 /// destination address. 284 /// 285 /// @param pkt DHCPv6 message to be checked. 286 /// @return false if the message has been sent to unicast address but it is 287 /// not allowed according to RFC3315, section 15; true otherwise. 288 bool testUnicast(const Pkt6Ptr& pkt) const; 289 290 /// @brief Verifies if specified packet meets RFC requirements 291 /// 292 /// Checks if mandatory option is really there, that forbidden option 293 /// is not there, and that client-id or server-id appears only once. 294 /// 295 /// @param pkt packet to be checked 296 /// @return false if the message should be dropped as a result of the 297 /// sanity check. 298 bool sanityCheck(const Pkt6Ptr& pkt); 299 300 /// @brief verifies if specified packet meets RFC requirements 301 /// 302 /// Checks if mandatory option is really there, that forbidden option 303 /// is not there, and that client-id or server-id appears only once. 304 /// 305 /// @param pkt packet to be checked 306 /// @param clientid expectation regarding client-id option 307 /// @param serverid expectation regarding server-id option 308 /// @throw RFCViolation if any issues are detected 309 void sanityCheck(const Pkt6Ptr& pkt, RequirementLevel clientid, 310 RequirementLevel serverid); 311 312 /// @brief verifies if received DUID option (client-id or server-id) is sane 313 /// 314 /// @param opt option to be checked 315 /// @param opt_name text name to be printed 316 /// @throw RFCViolation if any issues are detected 317 void sanityCheckDUID(const OptionPtr& opt, const std::string& opt_name); 318 319 /// @brief Processes incoming Solicit and returns response. 320 /// 321 /// Processes received Solicit message and verifies that its sender 322 /// should be served. In particular IA, TA and PD options are populated 323 /// with to-be assigned addresses, temporary addresses and delegated 324 /// prefixes, respectively. In the usual 4 message exchange, server is 325 /// expected to respond with Advertise message. However, if client 326 /// requests rapid-commit and server supports it, Reply will be sent 327 /// instead of Advertise and requested leases will be assigned 328 /// immediately. 329 /// 330 /// @param ctx Reference to client context 331 /// 332 /// @return Advertise, Reply message or NULL. 333 Pkt6Ptr processSolicit(AllocEngine::ClientContext6& ctx); 334 335 /// @brief Processes incoming Request and returns Reply response. 336 /// 337 /// Processes incoming Request message and verifies that its sender 338 /// should be served. In particular IA, TA and PD options are populated 339 /// with assigned addresses, temporary addresses and delegated 340 /// prefixes, respectively. Uses LeaseMgr to allocate or update existing 341 /// leases. 342 /// 343 /// @param ctx Reference to client context 344 /// 345 /// @return REPLY message or NULL 346 Pkt6Ptr processRequest(AllocEngine::ClientContext6& ctx); 347 348 /// @brief Processes incoming Renew message. 349 /// 350 /// @param ctx Reference to client context 351 /// 352 /// @return Reply message to be sent to the client. 353 Pkt6Ptr processRenew(AllocEngine::ClientContext6& ctx); 354 355 /// @brief Processes incoming Rebind message. 356 /// 357 /// @todo There are cases when the Rebind message should be discarded 358 /// by the DHCP server. One of those is when the server doesn't have a 359 /// record of the client and it is unable to determine whether the 360 /// client is on the appropriate link or not. We don't seem to do it 361 /// now. 362 /// 363 /// @param ctx Reference to client context 364 /// 365 /// @return Reply message to be sent to the client. 366 Pkt6Ptr processRebind(AllocEngine::ClientContext6& ctx); 367 368 /// @brief Processes incoming Confirm message and returns Reply. 369 /// 370 /// This function processes Confirm message from the client according 371 /// to section 18.3.3. of RFC 8415. It discards the Confirm message if 372 /// the message sent by the client contains no addresses, i.e. it has 373 /// no IA_NA options or all IA_NA options contain no IAAddr options. 374 /// 375 /// If the Confirm message contains addresses this function will perform 376 /// the following checks: 377 /// - check if there is appropriate subnet configured for the client 378 /// (e.g. subnet from which addresses are assigned for requests 379 /// received on the particular interface). 380 /// - check if all addresses sent in the Confirm message belong to the 381 /// selected subnet. 382 /// 383 /// If any of the checks above fails, the Reply message with the status 384 /// code NotOnLink is returned. Otherwise, the Reply message with the 385 /// status code Success is returned. 386 /// 387 /// @param ctx Reference to client context 388 /// 389 /// @return Reply message from the server or NULL pointer if Confirm 390 /// message should be discarded by the server. 391 Pkt6Ptr processConfirm(AllocEngine::ClientContext6& ctx); 392 393 /// @brief Process incoming Release message. 394 /// 395 /// @param ctx Reference to client context 396 /// 397 /// @return Reply message to be sent to the client. 398 Pkt6Ptr processRelease(AllocEngine::ClientContext6& ctx); 399 400 /// @brief Process incoming Decline message. 401 /// 402 /// This method processes Decline message. It conducts standard sanity 403 /// checks, creates empty reply and copies the necessary options from 404 /// the client's message. Finally, it calls @ref declineLeases, where 405 /// the actual address processing takes place. 406 /// 407 /// @param ctx Reference to client context 408 /// 409 /// @return Reply message to be sent to the client. 410 Pkt6Ptr processDecline(AllocEngine::ClientContext6& ctx); 411 412 /// @brief Processes incoming Information-request message. 413 /// 414 /// @param ctx Reference to client context 415 /// 416 /// @return Reply message to be sent to the client. 417 Pkt6Ptr processInfRequest(AllocEngine::ClientContext6& ctx); 418 419 /// @brief Processes incoming DHCPv4-query message. 420 /// 421 /// It always returns NULL, as there is nothing to be sent back to the 422 /// client at this time. The message was sent to DHCPv4 server using 423 /// @ref isc::dhcp::Dhcp6to4Ipc::handler()). We will send back a response 424 /// to the client once we get back DHCP4-REPLY from the DHCPv4 server. 425 /// 426 /// @param dhcp4_query message received from client 427 /// Does not throw 428 void processDhcp4Query(const Pkt6Ptr& dhcp4_query); 429 430 /// @brief Selects a subnet for a given client's packet. 431 /// 432 /// @param question client's message 433 /// @param drop if it is true the packet will be dropped 434 /// @return selected subnet (or NULL if no suitable subnet was found) 435 isc::dhcp::Subnet6Ptr selectSubnet(const Pkt6Ptr& question, bool& drop); 436 437 /// @brief Processes IA_NA option (and assigns addresses if necessary). 438 /// 439 /// Generates response to IA_NA. This typically includes selecting (and 440 /// allocating a lease in case of REQUEST) an address lease and creating 441 /// IAADDR option. In case of allocation failure, it may contain 442 /// status code option with non-zero status, denoting cause of the 443 /// allocation failure. 444 /// 445 /// @param query client's message (typically SOLICIT or REQUEST) 446 /// to the client (if the client sent this option to the server). 447 /// @param ctx client context (contains subnet, duid and other parameters) 448 /// @param ia pointer to client's IA_NA option (client's request) 449 /// 450 /// @return IA_NA option (server's response) 451 OptionPtr assignIA_NA(const isc::dhcp::Pkt6Ptr& query, 452 AllocEngine::ClientContext6& ctx, 453 Option6IAPtr ia); 454 455 /// @brief Processes IA_PD option (and assigns prefixes if necessary). 456 /// 457 /// Generates response to IA_PD. This typically includes selecting (and 458 /// allocating in the case of REQUEST) a prefix lease and creating an 459 /// IAPREFIX option. In case of an allocation failure, it may contain a 460 /// status code option with non-zero status denoting the cause of the 461 /// allocation failure. 462 /// 463 /// @param query client's message (typically SOLICIT or REQUEST) 464 /// @param ctx client context (contains subnet, duid and other parameters) 465 /// @param ia pointer to client's IA_PD option (client's request) 466 /// @return IA_PD option (server's response) 467 OptionPtr assignIA_PD(const Pkt6Ptr& query, 468 AllocEngine::ClientContext6& ctx, 469 boost::shared_ptr<Option6IA> ia); 470 471 /// @brief Extends lifetime of the specific IA_NA option. 472 /// 473 /// Generates response to IA_NA in Renew or Rebind. This typically includes 474 /// finding a lease that corresponds to the received address. If no such 475 /// lease is found, an IA_NA response is generated with an appropriate 476 /// status code. 477 /// 478 /// @param query client's message (Renew or Rebind) 479 /// to the client (if the client sent this option to the server). 480 /// @param ctx client context (contains subnet, duid and other parameters) 481 /// @param ia IA_NA option which carries address for which lease lifetime 482 /// will be extended. 483 /// @return IA_NA option (server's response) 484 OptionPtr extendIA_NA(const Pkt6Ptr& query, 485 AllocEngine::ClientContext6& ctx, 486 Option6IAPtr ia); 487 488 /// @brief Extends lifetime of the prefix. 489 /// 490 /// This function is called by the logic which processes Renew and Rebind 491 /// messages to extend the lifetime of the existing prefix. 492 /// 493 /// The behavior of this function is different than @c extendIA_NA in that 494 /// when there is no subnet found for the rebinding case, the Rebind message 495 /// is discarded by the server. That behavior is based on the following 496 /// statement from the RFC 8415, section 18.3.5: 497 /// 498 /// "If the server chooses to not include any IAs containing IA Address or 499 /// IA Prefix options with lifetimes of 0 and the server does not include 500 /// any other IAs with leases and/or status codes, the server does not send 501 /// a Reply message. In this situation, the server discards the Rebind 502 /// message". 503 /// 504 /// @todo We should consider unification of the server behavior for address 505 /// assignment and prefix delegation with respect to Rebind message 506 /// processing. The RFC 8415, section 18.3.5 doesn't really differentiate 507 /// between IA_NA and IA_PD in how they should be processed by the server. 508 /// The intention of the spec is as follows: 509 /// 510 /// - If the server finds a lease but addresses and/or prefixes are not 511 /// appropriate anymore, it sends them with zero lifetimes. 512 /// - If the server doesn't find a lease the server checks if the addresses 513 /// and/or prefixes the client sends are appropriate and sends them back 514 /// with zero lifetimes if they aren't. 515 /// - The server may choose to not respond at all, if it cannot determine 516 /// whether the addresses and/or prefixes are appropriate and it doesn't 517 /// allocate any other addresses and/or prefixes. 518 /// - If the server cannot find the leases included in the Rebind, the 519 /// server may either allocate the leases or simply return NoBinding. 520 /// 521 /// The @c extendIA_PD function drops the Rebind message if it cannot find 522 /// the client entry (as a result of not finding a subnet for the client), 523 /// the @c extendIA_NA function sends NoBinding status code in that case. 524 /// Perhaps we should introduce an "Authoritative" configuration flag which, 525 /// if enabled, would cause the server to always respond, either indicating 526 /// that the address/prefix is inappropriate (with zero lifetimes) or that 527 /// there is no binding (NoBinding status code) for both addresses and 528 /// prefixes. When the "Authoritative" flag is disabled the server would 529 /// drop the Rebind for which there is neither subnet selected nor client 530 /// entry found (as it could be handled by another DHCP server). If nothing 531 /// else we could consider unifying the behavior of @c extendIA_NA and 532 /// @c extendIA_PD with respect to Rebind processing. 533 /// 534 /// @param query client's message 535 /// @param ctx client context (contains subnet, duid and other parameters) 536 /// @param ia IA_PD option that is being renewed 537 /// @return IA_PD option (server's response) 538 /// @throw DHCPv6DiscardMessageError when the message being processed should 539 /// be discarded by the server, i.e. there is no binding for the client doing 540 /// Rebind. 541 OptionPtr extendIA_PD(const Pkt6Ptr& query, 542 AllocEngine::ClientContext6& ctx, 543 Option6IAPtr ia); 544 545 /// @brief Releases specific IA_NA option 546 /// 547 /// Generates response to IA_NA in Release message. This covers finding and 548 /// removal of a lease that corresponds to the received address. If no such 549 /// lease is found, an IA_NA response is generated with an appropriate 550 /// status code. 551 /// 552 /// The server sends top-level Status Code option. This method may update the 553 /// passed value of that option, i.e. general_status. It is set to SUCCESS when 554 /// message processing begins, but may be updated to some error code if the 555 /// release process fails. 556 /// 557 /// @param duid client's duid 558 /// @param query client's message 559 /// @param general_status a global status (it may be updated in case of errors) 560 /// @param ia IA_NA option that is being released 561 /// @param old_lease a pointer to the lease being released 562 /// @return IA_NA option (server's response) 563 OptionPtr releaseIA_NA(const DuidPtr& duid, const Pkt6Ptr& query, 564 int& general_status, 565 boost::shared_ptr<Option6IA> ia, 566 Lease6Ptr& old_lease); 567 568 /// @brief Releases specific IA_PD option 569 /// 570 /// Generates response to IA_PD in Release message. This covers finding and 571 /// removal of a lease that corresponds to the received prefix(es). If no such 572 /// lease is found, an IA_PD response is generated with an appropriate 573 /// status code. 574 /// 575 /// @param duid client's duid 576 /// @param query client's message 577 /// @param general_status a global status (it may be updated in case of errors) 578 /// @param ia IA_PD option that is being released 579 /// @param old_lease a pointer to the lease being released 580 /// @return IA_PD option (server's response) 581 OptionPtr releaseIA_PD(const DuidPtr& duid, const Pkt6Ptr& query, 582 int& general_status, 583 boost::shared_ptr<Option6IA> ia, 584 Lease6Ptr& old_lease); 585 586 /// @brief Copies required options from client message to server answer. 587 /// 588 /// Copies options that must appear in any server response (ADVERTISE, REPLY) 589 /// to client's messages (SOLICIT, REQUEST, RENEW, REBIND, DECLINE, RELEASE). 590 /// One notable example is client-id. Other options may be copied as required. 591 /// Relay information details are also copied here. 592 /// 593 /// @param question client's message (options will be copied from here) 594 /// @param answer server's message (options will be copied here) 595 void copyClientOptions(const Pkt6Ptr& question, Pkt6Ptr& answer); 596 597 /// @brief Build the configured option list 598 /// 599 /// @note The configured option list is an *ordered* list of 600 /// @c CfgOption objects used to append options to the response. 601 /// 602 /// @param question client's message 603 /// @param ctx client context (for the subnet) 604 /// @param co_list configured option list to build 605 void buildCfgOptionList(const Pkt6Ptr& question, 606 AllocEngine::ClientContext6& ctx, 607 CfgOptionList& co_list); 608 609 /// @brief Appends default options to server's answer. 610 /// 611 /// Adds required options to server's answer. In particular, server-id 612 /// is added. Possibly other mandatory options will be added, depending 613 /// on type (or content) of client message. 614 /// 615 /// @param question client's message 616 /// @param answer server's message (options will be added here) 617 /// @param co_list configured option list (currently unused) 618 void appendDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer, 619 const CfgOptionList& co_list); 620 621 /// @brief Appends requested options to server's answer. 622 /// 623 /// Appends options requested by client to the server's answer. 624 /// 625 /// @param question client's message 626 /// @param answer server's message (options will be added here) 627 /// 628 /// @param co_list configured option list 629 void appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer, 630 const CfgOptionList& co_list); 631 632 /// @brief Appends requested vendor options to server's answer. 633 /// 634 /// This is mostly useful for Cable Labs options for now, but the method 635 /// is easily extensible to other vendors. 636 /// 637 /// @param question client's message 638 /// @param answer server's message (vendor options will be added here) 639 /// @param ctx client context (contains subnet, duid and other parameters) 640 /// @param co_list configured option list 641 void appendRequestedVendorOptions(const Pkt6Ptr& question, Pkt6Ptr& answer, 642 AllocEngine::ClientContext6& ctx, 643 const CfgOptionList& co_list); 644 645 /// @brief Assigns leases. 646 /// 647 /// It supports non-temporary addresses (IA_NA) and prefixes (IA_PD). It 648 /// does NOT support temporary addresses (IA_TA). 649 /// 650 /// @param question client's message (with requested IA options) 651 /// @param answer server's message (IA options will be added here). 652 /// This message should contain Client FQDN option being sent by the server 653 /// to the client (if the client sent this option to the server). 654 /// @param ctx client context (contains subnet, duid and other parameters) 655 void assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer, 656 AllocEngine::ClientContext6& ctx); 657 658 /// @brief Processes Client FQDN Option. 659 /// 660 /// This function retrieves DHCPv6 Client FQDN %Option (if any) from the 661 /// packet sent by a client and takes necessary actions upon this option. 662 /// Received option comprises flags field which controls what DNS updates 663 /// server should do. Server may override client's preference based on 664 /// the current configuration. Server indicates that it has overridden 665 /// the preference by storing DHCPv6 Client FQDN option with the 666 /// appropriate flags in the response to a client. This option is also 667 /// used to communicate the client's domain-name which should be sent 668 /// to the DNS in the update. Again, server may act upon the received 669 /// domain-name, i.e. if the provided domain-name is partial it should 670 /// generate the fully qualified domain-name. 671 /// 672 /// This function takes into account the host reservation if one is matched 673 /// to this client when forming the FQDN to be used with DNS as well as the 674 /// lease name to be stored with the lease. In the following the term 675 /// "reserved hostname" means a host reservation which includes a 676 /// non-blank hostname. 677 /// 678 /// - If there is no Client FQDN and no reserved hostname then there 679 /// will no be DNS updates and the lease hostname will be empty. 680 /// 681 /// - If there is no Client FQDN but there is reserved hostname then 682 /// there will be no DNS updates and the lease hostname will be equal 683 /// to reserved hostname. 684 /// 685 /// - If there is a Client FQDN and a reserved hostname, then both the 686 /// FQDN and lease hostname will be equal to reserved hostname with 687 /// the qualifying suffix appended. 688 /// 689 /// - If there is a Client FQDN but no reserved hostname then both the 690 /// FQDN and lease hostname will be equal to the name provided in the 691 /// client FQDN adjusted according the DhcpDdns configuration 692 /// parameters (e.g.replace-client-name, qualifying suffix...). 693 /// 694 /// All the logic required to form appropriate answer to the client is 695 /// held in this function. 696 /// 697 /// @param question Client's message. 698 /// @param answer Server's response to a client. If server generated 699 /// Client FQDN option for the client, this option is stored in this 700 /// object. 701 /// @param ctx client context (includes subnet, client-id, hw-addr etc.) 702 void processClientFqdn(const Pkt6Ptr& question, const Pkt6Ptr& answer, 703 AllocEngine::ClientContext6& ctx); 704 705 /// @brief Creates a number of @c isc::dhcp_ddns::NameChangeRequest objects 706 /// based on the DHCPv6 Client FQDN %Option. 707 /// 708 /// The @c isc::dhcp_ddns::NameChangeRequest class encapsulates the request 709 /// from the DHCPv6 server to the DHCP-DDNS module to perform DNS Update. 710 /// The FQDN option carries response to the client about DNS updates that 711 /// server intends to perform for the DNS client. Based on this, the 712 /// function will create zero or more @c isc::dhcp_ddns::NameChangeRequest 713 /// objects and store them in the internal queue. To catch lease renewals 714 /// that alter the FQDN, the function first looks at the context's changed 715 /// list of leases (if any) to determine if DNS entries need to be removed. 716 /// It then looks at the valid leases to determine if any DNS entries need 717 /// to be added. If DNS updates are disabled, this method returns immediately. 718 /// 719 /// @todo Add support for multiple IAADDR options in the IA_NA. 720 /// 721 /// @param answer A message begins sent to the Client. If it holds the 722 /// @param ctx client context (contains subnet, duid and other parameters) 723 /// Client FQDN option, this option is used to create NameChangeRequests. 724 void createNameChangeRequests(const Pkt6Ptr& answer, 725 AllocEngine::ClientContext6& ctx); 726 727 /// @brief Attempts to extend the lifetime of IAs. 728 /// 729 /// This function is called when a client sends Renew or Rebind message. 730 /// It iterates through received IA options and attempts to extend 731 /// corresponding lease lifetimes. Internally, it calls 732 /// @c Dhcpv6Srv::extendIA_NA and @c Dhcpv6Srv::extendIA_PD to extend 733 /// the lifetime of IA_NA and IA_PD leases accordingly. 734 /// 735 /// @param query client's Renew or Rebind message 736 /// @param reply server's response 737 /// @param ctx client context (contains subnet, duid and other parameters) 738 void extendLeases(const Pkt6Ptr& query, Pkt6Ptr& reply, 739 AllocEngine::ClientContext6& ctx); 740 741 /// @brief Sets the T1 and T2 timers in the outbound IA 742 /// 743 /// This method determines the values for both the T1 and T2 744 /// timers for the given IA. It is influenced by the 745 /// lease's subnet's values for renew-timer, rebind-timer, 746 /// calculate-tee-times, t1-percent, and t2-percent as follows: 747 /// 748 /// T2: 749 /// 750 /// The value for T2 defaults to zero. If the rebind-timer value is 751 /// specified then use it. If not and calculate-tee-times is true, then 752 /// use the value given by: preferred lease time * t2-percent. 753 /// 754 /// T1: 755 /// 756 /// The candidate value for T1 defaults to zero. If the renew-timer value 757 /// is specified then use it. If not and calculate-tee-times is true, then 758 /// use the value given by: preferred lease time * t1-percent. 759 /// 760 /// The T1 candidate will be used provided it less than to T2, 761 /// otherwise it will be set T1 to zero. 762 /// 763 /// @param preferred_lft preferred lease time of the lease being assigned to the client 764 /// @param subnet the subnet to which the lease belongs 765 /// @param resp outbound IA option in which the timers are set. 766 void setTeeTimes(uint32_t preferred_lft, const Subnet6Ptr& subnet, Option6IAPtr& resp); 767 768 /// @brief Attempts to release received addresses 769 /// 770 /// It iterates through received IA_NA options and attempts to release 771 /// received addresses. If no such leases are found, or the lease fails 772 /// proper checks (e.g. belongs to someone else), a proper status 773 /// code is added to reply message. Released addresses are not added 774 /// to REPLY packet, just its IA_NA containers. 775 /// @param release client's message asking to release 776 /// @param reply server's response 777 /// @param ctx client context (includes subnet, client-id, hw-addr etc.) 778 void releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply, 779 AllocEngine::ClientContext6& ctx); 780 781 /// @brief converts DUID to text 782 /// Converts content of DUID option to a text representation, e.g. 783 /// 01:ff:02:03:06:80:90:ab:cd:ef 784 /// 785 /// @param opt option that contains DUID 786 /// @return string representation 787 static std::string duidToString(const OptionPtr& opt); 788 789 /// @brief dummy wrapper around IfaceMgr::receive6 790 /// 791 /// This method is useful for testing purposes, where its replacement 792 /// simulates reception of a packet. For that purpose it is protected. 793 virtual Pkt6Ptr receivePacket(int timeout); 794 795 /// @brief dummy wrapper around IfaceMgr::send() 796 /// 797 /// This method is useful for testing purposes, where its replacement 798 /// simulates transmission of a packet. For that purpose it is protected. 799 virtual void sendPacket(const Pkt6Ptr& pkt); 800 801 /// @brief Assigns incoming packet to zero or more classes. 802 /// 803 /// @note This is done in two phases: first the content of the 804 /// vendor-class-identifier option is used as a class, by 805 /// calling @ref classifyByVendor(). Second, the classification match 806 /// expressions are evaluated. The resulting classes will be stored 807 /// in the packet (see @ref isc::dhcp::Pkt6::classes_ and 808 /// @ref isc::dhcp::Pkt6::inClass). 809 /// 810 /// @param pkt packet to be classified 811 void classifyPacket(const Pkt6Ptr& pkt); 812 813 /// @brief Evaluate classes. 814 /// 815 /// @note Second part of the classification. 816 /// 817 /// Evaluate expressions of client classes: if it returns true the class 818 /// is added to the incoming packet. 819 /// 820 /// @param pkt packet to be classified. 821 /// @param depend_on_known if false classes depending on the KNOWN or 822 /// UNKNOWN classes are skipped, if true only these classes are evaluated. 823 void evaluateClasses(const Pkt6Ptr& pkt, bool depend_on_known); 824 825 /// @brief Assigns classes retrieved from host reservation database. 826 /// 827 /// @param pkt Pointer to the packet to which classes will be assigned. 828 /// @param ctx Reference to the client context. 829 void setReservedClientClasses(const Pkt6Ptr& pkt, 830 const AllocEngine::ClientContext6& ctx); 831 832 /// @brief Assigns classes retrieved from host reservation database 833 /// if they haven't been yet set. 834 /// 835 /// This function sets reserved client classes in case they haven't 836 /// been set after fetching host reservations from the database. 837 /// This is the case when the client has non-global host reservation 838 /// and the selected subnet belongs to a shared network. 839 /// 840 /// @param pkt Pointer to the packet to which classes will be assigned. 841 /// @param ctx Reference to the client context. 842 void conditionallySetReservedClientClasses(const Pkt6Ptr& pkt, 843 const AllocEngine::ClientContext6& ctx); 844 845 /// @brief Assigns incoming packet to zero or more classes (required pass). 846 /// 847 /// @note This required classification evaluates all classes which 848 /// were marked for required evaluation. Classes are collected so 849 /// evaluated in the reversed order than output option processing. 850 /// 851 /// @note The only-if-required flag is related because it avoids 852 /// double evaluation (which is not forbidden). 853 /// 854 /// @param pkt packet to be classified 855 /// @param ctx allocation context where to get information 856 void requiredClassify(const Pkt6Ptr& pkt, AllocEngine::ClientContext6& ctx); 857 858 /// @brief Attempts to get a MAC/hardware address using configured sources 859 /// 860 /// Tries to extract MAC/hardware address information from the packet 861 /// using MAC sources configured in 'mac-sources' configuration parameter. 862 /// 863 /// @param pkt will try to exact MAC address from this packet 864 /// @return HWaddr pointer (or NULL if configured methods fail) 865 static HWAddrPtr getMAC(const Pkt6Ptr& pkt); 866 867 /// @brief Processes Relay-supplied options, if present 868 /// 869 /// This method implements RFC6422. It checks if there are any RSOO options 870 /// inserted by the relay agents in the query message. If there are, they 871 /// are copied over to the response if they meet the following criteria: 872 /// - the option is marked as RSOO-enabled (see relay-supplied-options 873 /// configuration parameter) 874 /// - there is no such option provided by the server) 875 void processRSOO(const Pkt6Ptr& query, const Pkt6Ptr& rsp); 876 877 /// @brief Initializes client context for specified packet 878 /// 879 /// This method: 880 /// - Performs the subnet selection and stores the result in context 881 /// - Extracts the duid from the packet and saves it to the context 882 /// - Extracts the hardware address from the packet and saves it to 883 /// the context 884 /// - Performs host reservation lookup and stores the result in the 885 /// context 886 /// 887 /// Even though the incoming packet type is known to this method, it 888 /// doesn't set the @c fake_allocation flag, because of a possibility 889 /// that the Rapid Commit option is in use. The @c fake_allocation 890 /// flag is set appropriately after it has been determined whether 891 /// the Rapid Commit option was included and that the server respects 892 /// it. 893 /// 894 /// @param pkt pointer to a packet for which context will be created. 895 /// @param [out] ctx reference to context object to be initialized. 896 /// @param [out] drop if it is true the packet will be dropped. 897 void initContext(const Pkt6Ptr& pkt, 898 AllocEngine::ClientContext6& ctx, 899 bool& drop); 900 901 /// @brief this is a prefix added to the content of vendor-class option 902 /// 903 /// If incoming packet has a vendor class option, its content is 904 /// prepended with this prefix and then interpreted as a class. 905 /// For example, a packet that sends vendor class with value of "FOO" 906 /// will cause the packet to be assigned to class VENDOR_CLASS_FOO. 907 static const std::string VENDOR_CLASS_PREFIX; 908 909 /// @brief Attempts to decline all leases in specified Decline message. 910 /// 911 /// This method iterates over all IA_NA options and calls @ref declineIA on 912 /// each of them. 913 /// 914 /// @param decline Decline message sent by a client 915 /// @param reply Server's response (IA_NA with status will be added here) 916 /// @param ctx context 917 /// @return true when expected to continue, false when hooks told us to drop 918 /// the packet 919 bool declineLeases(const Pkt6Ptr& decline, Pkt6Ptr& reply, 920 AllocEngine::ClientContext6& ctx); 921 922 /// @brief Declines leases in a single IA_NA option 923 /// 924 /// This method iterates over all addresses in this IA_NA, verifies 925 /// whether they belong to the client and calls @ref declineLease. If there's 926 /// an error, general_status (a status put in the top level scope), will be 927 /// updated. 928 /// 929 /// @param decline client's Decline message 930 /// @param duid client's duid (used to verify if the client owns the lease) 931 /// @param general_status [out] status in top-level message (may be updated) 932 /// @param ia specific IA_NA option to process. 933 /// @param new_leases a collection of leases being declined. 934 /// @return IA_NA option with response (to be included in Reply message) 935 OptionPtr 936 declineIA(const Pkt6Ptr& decline, const DuidPtr& duid, int& general_status, 937 boost::shared_ptr<Option6IA> ia, Lease6Collection& new_leases); 938 939 /// @brief Declines specific IPv6 lease. 940 /// 941 /// This method performs the actual decline and all necessary operations: 942 /// - cleans up DNS, if necessary 943 /// - updates subnet[X].declined-addresses (per subnet stat) 944 /// - updates declined-addresses (global stat) 945 /// - disassociates client information from the lease 946 /// - moves the lease to DECLINED state 947 /// - sets lease expiration time to decline-probation-period 948 /// - adds status-code success 949 /// 950 /// @param decline used for generating removal Name Change Request. 951 /// @param lease lease to be declined 952 /// @param ia_rsp response IA_NA. 953 /// @return true when expected to continue, false when hooks told us to drop 954 /// the packet 955 bool declineLease(const Pkt6Ptr& decline, const Lease6Ptr lease, 956 boost::shared_ptr<Option6IA> ia_rsp); 957 958 /// @brief A simple utility method that sets the status code 959 /// 960 /// Removes old status code and sets a new one. 961 /// @param container status code will be added here 962 /// @param status status code option 963 void setStatusCode(boost::shared_ptr<Option6IA>& container, 964 const OptionPtr& status); 965 966 /// @brief Iterates over new leases, update stale DNS entries 967 /// 968 /// Checks the context's current subnet (most recently selected) against 969 /// an original selected subnet. If they are the same the function 970 /// simply returns. 971 /// 972 /// If they differ, we treat this as a dynamic subnet change made by the 973 /// allocation engine. It is possible that DDNS subnet parameters for 974 /// the new subnet are different and this needs to handled. We first 975 /// save the current DNS-related values from the context and then 976 /// re-run processClientFqdn(). This will rebuild the FQDN option 977 /// to send back to the client based on the new subnet as well as 978 /// update the context. If the new values are different from the 979 /// previous values, we iterate over the leases and update the 980 /// DNS values. 981 /// 982 /// @param question Client's message. 983 /// @param answer Server's response to a client. If server generated 984 /// @param ctx client context (contains subnet, duid and other parameters) 985 /// @param orig_subnet the originally selected subnet 986 /// 987 /// @note 988 /// Subnet may be modified by the allocation engine, if the initial subnet 989 /// belongs to a shared network. Note that this will only handle cases 990 /// where all IA_xx's in a client request result in a subnet change. It is 991 /// possible, currently, for the last IA_xx in request to end up using the 992 /// same subnet as originally selected, and we will miss a change incurred 993 /// by preceding IA_xx's. In general users should be strongly encouraged to 994 /// avoid situations where all of the following are true: 995 /// 996 /// 1. clients send more than one IA_xx in a query 997 /// 2. subnets in the shared-network are equally eligible (i.e don't have 998 /// class guards etc) 999 /// 3. subnets have differing options or DDNS parameters 1000 // 1001 void checkDynamicSubnetChange(const Pkt6Ptr& question, Pkt6Ptr& answer, 1002 AllocEngine::ClientContext6& ctx, 1003 const Subnet6Ptr orig_subnet); 1004 public: 1005 1006 /// Used for DHCPv4-over-DHCPv6 too. 1007 1008 /// @brief Check if the last relay added a relay-source-port option. 1009 /// 1010 /// @param query DHCPv6 message to be checked. 1011 /// @return the port to use to join the relay or 0 for the default. 1012 static uint16_t checkRelaySourcePort(const Pkt6Ptr& query); 1013 1014 private: 1015 1016 /// @public 1017 /// @brief Assign class using vendor-class-identifier option 1018 /// 1019 /// @note This is the first part of @ref classifyPacket 1020 /// 1021 /// @param pkt packet to be classified 1022 /// @param classes a reference to added class names for logging 1023 void classifyByVendor(const Pkt6Ptr& pkt, std::string& classes); 1024 1025 /// @brief Update FQDN based on the reservations in the current subnet. 1026 /// 1027 /// When shared networks are in use the allocation engine may switch to 1028 /// a different subnet than originally selected. If this new subnet has 1029 /// hostname reservations there is a need to update the FQDN option 1030 /// value. 1031 /// 1032 /// This method should be called after lease assignments to perform 1033 /// such update when required. 1034 /// 1035 /// @param ctx Client context. 1036 /// @param answer Message being sent to a client, which may hold an FQDN 1037 /// option to be updated. 1038 /// 1039 /// @throw isc::Unexpected if specified message is NULL. This is treated 1040 /// as a programmatic error. 1041 void updateReservedFqdn(AllocEngine::ClientContext6& ctx, 1042 const Pkt6Ptr& answer); 1043 1044 /// @private 1045 /// @brief Generate FQDN to be sent to a client if none exists. 1046 /// 1047 /// This function is meant to be called by the functions which process 1048 /// client's messages. The function should be called after a function 1049 /// which creates FQDN option for the client. This option must exist 1050 /// in the answer message specified as an argument. It must also be 1051 /// called after functions which assign leases for a client. The 1052 /// IA options being a result of lease acquisition must be appended 1053 /// to the message specified as a parameter. 1054 /// 1055 /// If the Client FQDN option being present in the message carries empty 1056 /// hostname, this function will attempt to generate hostname from the 1057 /// IPv6 address being acquired by the client. The IPv6 address is retrieved 1058 /// from the IA_NA option carried in the specified message. If multiple 1059 /// addresses are present in the particular IA_NA option or multiple IA_NA 1060 /// options exist, the first address found is selected. 1061 /// 1062 /// The IPv6 address is converted to the hostname using the following 1063 /// pattern: 1064 /// @code 1065 /// prefix-converted-ip-address.domain-name-suffix. 1066 /// @endcode 1067 /// where: 1068 /// - prefix is a configurable prefix string appended to all auto-generated 1069 /// hostnames. 1070 /// - converted-ip-address is created by replacing all colons from the IPv6 1071 /// address with hyphens. 1072 /// - domain-name-suffix is a suffix for a domain name that, together with 1073 /// the other parts, constitute the fully qualified domain name. 1074 /// 1075 /// When hostname is successfully generated, it is either used to update 1076 /// FQDN-related fields in a lease database or to update the Client FQDN 1077 /// option being sent back to the client. The lease database update is 1078 /// NOT performed if Advertise message is being processed. 1079 /// 1080 /// @param answer Message being sent to a client, which may hold IA_NA 1081 /// and Client FQDN options to be used to generate name for a client. 1082 /// @param ctx Client context. 1083 /// 1084 /// @throw isc::Unexpected if specified message is NULL. This is treated 1085 /// as a programmatic error. 1086 void generateFqdn(const Pkt6Ptr& answer, 1087 AllocEngine::ClientContext6& ctx); 1088 1089 /// @brief Updates statistics for received packets 1090 /// @param query packet received 1091 static void processStatsReceived(const Pkt6Ptr& query); 1092 1093 /// @brief Checks if the specified option code has been requested using 1094 /// the Option Request option. 1095 /// 1096 /// @param query Pointer to the client's query. 1097 /// @parma code Option code. 1098 /// 1099 /// @return true if option has been requested in the ORO. 1100 bool requestedInORO(const Pkt6Ptr& query, const uint16_t code) const; 1101 1102 protected: 1103 /// UDP port number on which server listens. 1104 uint16_t server_port_; 1105 1106 /// UDP port number to which server sends all responses. 1107 uint16_t client_port_; 1108 1109 public: 1110 1111 /// @note used by DHCPv4-over-DHCPv6 so must be public and static 1112 1113 /// @brief Updates statistics for transmitted packets 1114 /// @param response packet transmitted 1115 static void processStatsSent(const Pkt6Ptr& response); 1116 1117 /// @brief Returns the index of the buffer6_send hook 1118 /// @return the index of the buffer6_send hook 1119 static int getHookIndexBuffer6Send(); 1120 1121 /// @brief Executes buffer6_send callout and sends the response. 1122 /// 1123 /// @param callout_handle pointer to the callout handle. 1124 /// @param rsp pointer to a response. 1125 void processPacketBufferSend(hooks::CalloutHandlePtr& callout_handle, 1126 Pkt6Ptr& rsp); 1127 1128 /// @brief Return a list of all paths that contain passwords or secrets for 1129 /// kea-dhcp6. 1130 /// 1131 /// @return the list of lists of sequential JSON map keys needed to reach 1132 /// the passwords and secrets. 1133 std::list<std::list<std::string>> jsonPathsToRedact() const final override; 1134 1135 protected: 1136 1137 /// Server DUID (to be sent in server-identifier option) 1138 OptionPtr serverid_; 1139 1140 /// Indicates if shutdown is in progress. Setting it to true will 1141 /// initiate server shutdown procedure. 1142 volatile bool shutdown_; 1143 1144 /// @brief Executes pkt6_send callout. 1145 /// 1146 /// @param callout_handle pointer to the callout handle. 1147 /// @param query Pointer to a query. 1148 /// @param rsp Pointer to a response. 1149 void processPacketPktSend(hooks::CalloutHandlePtr& callout_handle, 1150 Pkt6Ptr& query, Pkt6Ptr& rsp); 1151 1152 /// @brief Allocation Engine. 1153 /// Pointer to the allocation engine that we are currently using 1154 /// It must be a pointer, because we will support changing engines 1155 /// during normal operation (e.g. to use different allocators) 1156 boost::shared_ptr<AllocEngine> alloc_engine_; 1157 1158 /// Holds a list of @c isc::dhcp_ddns::NameChangeRequest objects, which 1159 /// are waiting for sending to kea-dhcp-ddns module. 1160 std::queue<isc::dhcp_ddns::NameChangeRequest> name_change_reqs_; 1161 1162 /// @brief Holds information about disabled DHCP service and/or 1163 /// disabled subnet/network scopes. 1164 NetworkStatePtr network_state_; 1165 1166 /// @brief Controls access to the configuration backends. 1167 CBControlDHCPv6Ptr cb_control_; 1168 }; 1169 1170 } // namespace dhcp 1171 } // namespace isc 1172 1173 #endif // DHCP6_SRV_H 1174