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 DHCPV4_SRV_H 8 #define DHCPV4_SRV_H 9 10 #include <asiolink/io_service.h> 11 #include <dhcp/dhcp4.h> 12 #include <dhcp/option.h> 13 #include <dhcp/option_string.h> 14 #include <dhcp/option4_client_fqdn.h> 15 #include <dhcp/option_custom.h> 16 #include <dhcp/pkt4.h> 17 #include <dhcp_ddns/ncr_msg.h> 18 #include <dhcpsrv/alloc_engine.h> 19 #include <dhcpsrv/callout_handle_store.h> 20 #include <dhcpsrv/cb_ctl_dhcp4.h> 21 #include <dhcpsrv/cfg_option.h> 22 #include <dhcpsrv/d2_client_mgr.h> 23 #include <dhcpsrv/network_state.h> 24 #include <dhcpsrv/subnet.h> 25 #include <hooks/callout_handle.h> 26 #include <process/daemon.h> 27 28 #include <functional> 29 #include <iostream> 30 #include <queue> 31 32 // Undefine the macro OPTIONAL which is defined in some operating 33 // systems but conflicts with a member of the RequirementLevel enum in 34 // the server class. 35 36 #ifdef OPTIONAL 37 #undef OPTIONAL 38 #endif 39 40 namespace isc { 41 namespace dhcp { 42 43 /// @brief DHCPv4 message exchange. 44 /// 45 /// This class represents the DHCPv4 message exchange. The message exchange 46 /// consists of the single client message, server response to this message 47 /// and the mechanisms to generate the server's response. The server creates 48 /// the instance of the @c Dhcpv4Exchange for each inbound message that it 49 /// accepts for processing. 50 /// 51 /// The use of the @c Dhcpv4Exchange object as a central repository of 52 /// information about the message exchange simplifies the API of the 53 /// @c Dhcpv4Srv class. 54 /// 55 /// Another benefit of using this class is that different methods of the 56 /// @c Dhcpv4Srv may share information. For example, the constructor of this 57 /// class selects the subnet and multiple methods of @c Dhcpv4Srv use this 58 /// subnet, without the need to select it again. 59 /// 60 /// @todo This is the initial version of this class. In the future a lot of 61 /// code from the @c Dhcpv4Srv class will be migrated here. 62 class Dhcpv4Exchange { 63 public: 64 /// @brief Constructor. 65 /// 66 /// The constructor selects the subnet for the query and checks for the 67 /// static host reservations for the client which has sent the message. 68 /// The information about the reservations is stored in the 69 /// @c AllocEngine::ClientContext4 object, which can be obtained by 70 /// calling the @c getContext. 71 /// 72 /// @param alloc_engine Pointer to the instance of the Allocation Engine 73 /// used by the server. 74 /// @param query Pointer to the client message. 75 /// @param subnet Pointer to the subnet to which the client belongs. 76 /// @param drop if it is true the packet will be dropped. 77 Dhcpv4Exchange(const AllocEnginePtr& alloc_engine, const Pkt4Ptr& query, 78 const Subnet4Ptr& subnet, bool& drop); 79 80 /// @brief Initializes the instance of the response message. 81 /// 82 /// The type of the response depends on the type of the query message. 83 /// For the DHCPDISCOVER the DHCPOFFER is created. For the DHCPREQUEST 84 /// and DHCPINFORM the DHCPACK is created. For the DHCPRELEASE the 85 /// response is not initialized. 86 void initResponse(); 87 88 /// @brief Initializes the DHCPv6 part of the response message 89 /// 90 /// Called by initResponse() when the query is a DHCP4o6 message 91 void initResponse4o6(); 92 93 /// @brief Returns the pointer to the query from the client. getQuery()94 Pkt4Ptr getQuery() const { 95 return (query_); 96 } 97 98 /// @brief Returns the pointer to the server's response. 99 /// 100 /// The returned pointer is NULL if the query type is DHCPRELEASE or DHCPDECLINE. getResponse()101 Pkt4Ptr getResponse() const { 102 return (resp_); 103 } 104 105 /// @brief Removes the response message by resetting the pointer to NULL. deleteResponse()106 void deleteResponse() { 107 resp_.reset(); 108 } 109 110 /// @brief Returns the copy of the context for the Allocation engine. getContext()111 AllocEngine::ClientContext4Ptr getContext() const { 112 return (context_); 113 } 114 115 /// @brief Returns the configured option list (non-const version) getCfgOptionList()116 CfgOptionList& getCfgOptionList() { 117 return (cfg_option_list_); 118 } 119 120 /// @brief Returns the configured option list (const version) getCfgOptionList()121 const CfgOptionList& getCfgOptionList() const { 122 return (cfg_option_list_); 123 } 124 125 /// @brief Sets reserved values of siaddr, sname and file in the 126 /// server's response. 127 void setReservedMessageFields(); 128 129 /// @brief Assigns classes retrieved from host reservation database. 130 /// 131 /// @param context pointer to the context. 132 static void setReservedClientClasses(AllocEngine::ClientContext4Ptr context); 133 134 /// @brief Assigns classes retrieved from host reservation database 135 /// if they haven't been yet set. 136 /// 137 /// This function sets reserved client classes in case they haven't 138 /// been set after fetching host reservations from the database. 139 /// This is the case when the client has non-global host reservation 140 /// and the selected subnet belongs to a shared network. 141 void conditionallySetReservedClientClasses(); 142 143 /// @brief Assigns incoming packet to zero or more classes. 144 /// 145 /// @note This is done in two phases: first the content of the 146 /// vendor-class-identifier option is used as a class, by 147 /// calling @ref classifyByVendor(). Second, the classification match 148 /// expressions are evaluated. The resulting classes will be stored 149 /// in the packet (see @ref isc::dhcp::Pkt4::classes_ and 150 /// @ref isc::dhcp::Pkt4::inClass). 151 /// 152 /// @param pkt packet to be classified 153 static void classifyPacket(const Pkt4Ptr& pkt); 154 155 private: 156 157 /// @public 158 /// @brief Assign class using vendor-class-identifier option 159 /// 160 /// @note This is the first part of @ref classifyPacket 161 /// 162 /// @param pkt packet to be classified 163 static void classifyByVendor(const Pkt4Ptr& pkt); 164 165 /// @brief Evaluate classes. 166 /// 167 /// @note Second part of the classification. 168 /// 169 /// Evaluate expressions of client classes: if it returns true the class 170 /// is added to the incoming packet. 171 /// 172 /// @param pkt packet to be classified. 173 /// @param depend_on_known if false classes depending on the KNOWN or 174 /// UNKNOWN classes are skipped, if true only these classes are evaluated. 175 static void evaluateClasses(const Pkt4Ptr& pkt, bool depend_on_known); 176 177 /// @brief Copies default parameters from client's to server's message 178 /// 179 /// Some fields are copied from client's message into server's response, 180 /// e.g. client HW address, number of hops, transaction-id etc. 181 /// 182 /// @warning This message is called internally by @c initResponse and 183 /// thus it doesn't check if the resp_ value has been initialized. The 184 /// calling method is responsible for making sure that @c resp_ is 185 /// not NULL. 186 void copyDefaultFields(); 187 188 /// @brief Copies default options from client's to server's message 189 /// 190 /// Some options are copied from client's message into server's response, 191 /// e.g. Relay Agent Info option, Subnet Selection option etc. 192 /// 193 /// @warning This message is called internally by @c initResponse and 194 /// thus it doesn't check if the resp_ value has been initialized. The 195 /// calling method is responsible for making sure that @c resp_ is 196 /// not NULL. 197 void copyDefaultOptions(); 198 199 /// @brief Set host identifiers within a context. 200 /// 201 /// This method sets an ordered list of host identifier types and 202 /// values which the server should use to find host reservations. 203 /// The order of the set is determined by the configuration parameter, 204 /// host-reservation-identifiers 205 void setHostIdentifiers(); 206 207 /// @brief Pointer to the allocation engine used by the server. 208 AllocEnginePtr alloc_engine_; 209 210 /// @brief Pointer to the DHCPv4 message sent by the client. 211 Pkt4Ptr query_; 212 213 /// @brief Pointer to the DHCPv4 message to be sent to the client. 214 Pkt4Ptr resp_; 215 216 /// @brief Context for use with allocation engine. 217 AllocEngine::ClientContext4Ptr context_; 218 219 /// @brief Configured option list. 220 /// @note The configured option list is an *ordered* list of 221 /// @c CfgOption objects used to append options to the response. 222 CfgOptionList cfg_option_list_; 223 }; 224 225 /// @brief Type representing the pointer to the @c Dhcpv4Exchange. 226 typedef boost::shared_ptr<Dhcpv4Exchange> Dhcpv4ExchangePtr; 227 228 229 /// @brief DHCPv4 server service. 230 /// 231 /// This singleton class represents DHCPv4 server. It contains all 232 /// top-level methods and routines necessary for server operation. 233 /// In particular, it instantiates IfaceMgr, loads or generates DUID 234 /// that is going to be used as server-identifier, receives incoming 235 /// packets, processes them, manages leases assignment and generates 236 /// appropriate responses. 237 /// 238 /// This class does not support any controlling mechanisms directly. 239 /// See the derived \ref ControlledDhcpv4Srv class for support for 240 /// command and configuration updates over msgq. 241 class Dhcpv4Srv : public process::Daemon { 242 private: 243 244 /// @brief Pointer to IO service used by the server. 245 asiolink::IOServicePtr io_service_; 246 247 public: 248 249 /// @brief defines if certain option may, must or must not appear 250 typedef enum { 251 FORBIDDEN, 252 MANDATORY, 253 OPTIONAL 254 } RequirementLevel; 255 256 /// @brief Default constructor. 257 /// 258 /// Instantiates necessary services, required to run DHCPv4 server. 259 /// In particular, creates IfaceMgr that will be responsible for 260 /// network interaction. Will instantiate lease manager, and load 261 /// old or create new DUID. It is possible to specify alternate 262 /// port on which DHCPv4 server will listen on and alternate port 263 /// where DHCPv4 server sends all responses to. Those are mostly useful 264 /// for testing purposes. The Last two arguments of the constructor 265 /// should be left at default values for normal server operation. 266 /// They should be set to 'false' when creating an instance of this 267 /// class for unit testing because features they enable require 268 /// root privileges. 269 /// 270 /// @param server_port specifies port number to listen on 271 /// @param client_port specifies port number to send to 272 /// @param use_bcast configure sockets to support broadcast messages. 273 /// @param direct_response_desired specifies if it is desired to 274 /// use direct V4 traffic. 275 Dhcpv4Srv(uint16_t server_port = DHCP4_SERVER_PORT, 276 uint16_t client_port = 0, 277 const bool use_bcast = true, 278 const bool direct_response_desired = true); 279 280 /// @brief Destructor. Used during DHCPv4 service shutdown. 281 virtual ~Dhcpv4Srv(); 282 283 /// @brief Checks if the server is running in unit test mode. 284 /// 285 /// @return true if the server is running in unit test mode, 286 /// false otherwise. inTestMode()287 bool inTestMode() const { 288 return (server_port_ == 0); 289 } 290 291 /// @brief Returns pointer to the IO service used by the server. getIOService()292 asiolink::IOServicePtr& getIOService() { 293 return (io_service_); 294 } 295 296 /// @brief Returns pointer to the network state used by the server. getNetworkState()297 NetworkStatePtr& getNetworkState() { 298 return (network_state_); 299 } 300 301 /// @brief Returns an object which controls access to the configuration 302 /// backends. 303 /// 304 /// @return Pointer to the instance of the object which controls 305 /// access to the configuration backends. getCBControl()306 CBControlDHCPv4Ptr getCBControl() const { 307 return (cb_control_); 308 } 309 310 /// @brief returns Kea version on stdout and exit. 311 /// redeclaration/redefinition. @ref isc::process::Daemon::getVersion() 312 static std::string getVersion(bool extended); 313 314 /// @brief Main server processing loop. 315 /// 316 /// Main server processing loop. Call the processing step routine 317 /// until shut down. 318 /// 319 /// @return The value returned by @c Daemon::getExitValue(). 320 int run(); 321 322 /// @brief Main server processing step. 323 /// 324 /// Main server processing step. Receives one incoming packet, calls 325 /// the processing packet routing and (if necessary) transmits 326 /// a response. 327 void run_one(); 328 329 /// @brief Process a single incoming DHCPv4 packet and sends the response. 330 /// 331 /// It verifies correctness of the passed packet, calls per-type processXXX 332 /// methods, generates appropriate answer, sends the answer to the client. 333 /// 334 /// @param query A pointer to the packet to be processed. 335 void processPacketAndSendResponse(Pkt4Ptr& query); 336 337 /// @brief Process a single incoming DHCPv4 packet and sends the response. 338 /// 339 /// It verifies correctness of the passed packet, calls per-type processXXX 340 /// methods, generates appropriate answer, sends the answer to the client. 341 /// 342 /// @param query A pointer to the packet to be processed. 343 void processPacketAndSendResponseNoThrow(Pkt4Ptr& query); 344 345 /// @brief Process an unparked DHCPv4 packet and sends the response. 346 /// 347 /// @param callout_handle pointer to the callout handle. 348 /// @param query A pointer to the packet to be processed. 349 /// @param rsp A pointer to the response. 350 void sendResponseNoThrow(hooks::CalloutHandlePtr& callout_handle, 351 Pkt4Ptr& query, Pkt4Ptr& rsp); 352 353 /// @brief Process a single incoming DHCPv4 packet. 354 /// 355 /// It verifies correctness of the passed packet, calls per-type processXXX 356 /// methods, generates appropriate answer. 357 /// 358 /// @param query A pointer to the packet to be processed. 359 /// @param rsp A pointer to the response. 360 /// @param allow_packet_park Indicates if parking a packet is allowed. 361 void processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp, 362 bool allow_packet_park = true); 363 364 /// @brief Process a single incoming DHCPv4 query. 365 /// 366 /// It calls per-type processXXX methods, generates appropriate answer. 367 /// 368 /// @param query A pointer to the packet to be processed. 369 /// @param rsp A pointer to the response. 370 /// @param allow_packet_park Indicates if parking a packet is allowed. 371 void processDhcp4Query(Pkt4Ptr& query, Pkt4Ptr& rsp, 372 bool allow_packet_park); 373 374 /// @brief Process a single incoming DHCPv4 query. 375 /// 376 /// It calls per-type processXXX methods, generates appropriate answer, 377 /// sends the answer to the client. 378 /// 379 /// @param query A pointer to the packet to be processed. 380 /// @param rsp A pointer to the response. 381 /// @param allow_packet_park Indicates if parking a packet is allowed. 382 void processDhcp4QueryAndSendResponse(Pkt4Ptr& query, Pkt4Ptr& rsp, 383 bool allow_packet_park); 384 385 /// @brief Instructs the server to shut down. 386 void shutdown() override; 387 388 /// 389 /// @name Public accessors returning values required to (re)open sockets. 390 /// 391 //@{ 392 /// 393 /// @brief Get UDP port on which server should listen. 394 /// 395 /// Typically, server listens on UDP port number 67. Other ports are used 396 /// for testing purposes only. 397 /// 398 /// @return UDP port on which server should listen. getServerPort()399 uint16_t getServerPort() const { 400 return (server_port_); 401 } 402 403 /// @brief Return bool value indicating that broadcast flags should be set 404 /// on sockets. 405 /// 406 /// @return A bool value indicating that broadcast should be used (if true). useBroadcast()407 bool useBroadcast() const { 408 return (use_bcast_); 409 } 410 //@} 411 412 /// @brief Starts DHCP_DDNS client IO if DDNS updates are enabled. 413 /// 414 /// If updates are enabled, it instructs the D2ClientMgr singleton to 415 /// enter send mode. If D2ClientMgr encounters errors it may throw 416 /// D2ClientError. This method does not catch exceptions. 417 void startD2(); 418 419 /// @brief Stops DHCP_DDNS client IO if DDNS updates are enabled. 420 /// 421 /// If updates are enabled, it instructs the D2ClientMgr singleton to 422 /// leave send mode. If D2ClientMgr encounters errors it may throw 423 /// D2ClientError. This method does not catch exceptions. 424 void stopD2(); 425 426 /// @brief Implements the error handler for DHCP_DDNS IO errors 427 /// 428 /// Invoked when a NameChangeRequest send to kea-dhcp-ddns completes with 429 /// a failed status. These are communications errors, not data related 430 /// failures. 431 /// 432 /// This method logs the failure and then suspends all further updates. 433 /// Updating can only be restored by reconfiguration or restarting the 434 /// server. There is currently no retry logic so the first IO error that 435 /// occurs will suspend updates. 436 /// @todo We may wish to make this more robust or sophisticated. 437 /// 438 /// @param result Result code of the send operation. 439 /// @param ncr NameChangeRequest which failed to send. 440 virtual void d2ClientErrorHandler(const dhcp_ddns:: 441 NameChangeSender::Result result, 442 dhcp_ddns::NameChangeRequestPtr& ncr); 443 444 /// @brief Discards parked packets 445 /// Clears the packet parking lots of all packets. 446 /// Called during reconfigure and shutdown. 447 void discardPackets(); 448 449 /// @brief Returns value of the test_send_responses_to_source_ flag. 450 /// 451 /// @return value of the test_send_responses_to_source_ flag. getSendResponsesToSource()452 bool getSendResponsesToSource() const { 453 return (test_send_responses_to_source_); 454 } 455 456 protected: 457 458 /// @name Functions filtering and sanity-checking received messages. 459 /// 460 /// @todo These functions are supposed to be moved to a new class which 461 /// will manage different rules for accepting and rejecting messages. 462 /// Perhaps ticket #3116 is a good opportunity to do it. 463 /// 464 //@{ 465 /// @brief Checks whether received message should be processed or discarded. 466 /// 467 /// This function checks whether received message should be processed or 468 /// discarded. It should be called on the beginning of message processing 469 /// (just after the message has been decoded). This message calls a number 470 /// of other functions which check whether message should be processed, 471 /// using different criteria. 472 /// 473 /// This function should be extended when new criteria for accepting 474 /// received message have to be implemented. This function is meant to 475 /// aggregate all early filtering checks on the received message. By having 476 /// a single function like this, we are avoiding bloat of the server's main 477 /// loop. 478 /// 479 /// @warning This function should remain exception safe. 480 /// 481 /// @param query Received message. 482 /// 483 /// @return true if the message should be further processed, or false if 484 /// the message should be discarded. 485 bool accept(const Pkt4Ptr& query) const; 486 487 /// @brief Check if a message sent by directly connected client should be 488 /// accepted or discarded. 489 /// 490 /// This function checks if the received message is from directly connected 491 /// client. If it is, it checks that it should be processed or discarded. 492 /// 493 /// Note that this function doesn't validate all addresses being carried in 494 /// the message. The primary purpose of this function is to filter out 495 /// direct messages in the local network for which there is no suitable 496 /// subnet configured. For example, this function accepts unicast messages 497 /// because unicasts may be used by clients located in remote networks to 498 /// to renew existing leases. If their notion of address is wrong, the 499 /// server will have to sent a NAK, instead of dropping the message. 500 /// Detailed validation of such messages is performed at later stage of 501 /// processing. 502 /// 503 /// This function accepts the following messages: 504 /// - all valid relayed messages, 505 /// - all unicast messages, 506 /// - all broadcast messages except DHCPINFORM received on the interface 507 /// for which the suitable subnet exists (is configured). 508 /// - all DHCPINFORM messages with source address or ciaddr set. 509 /// 510 /// @param query Message sent by a client. 511 /// 512 /// @return true if message is accepted for further processing, false 513 /// otherwise. 514 bool acceptDirectRequest(const Pkt4Ptr& query) const; 515 516 /// @brief Check if received message type is valid for the server to 517 /// process. 518 /// 519 /// This function checks that the received message type belongs to 520 /// the range of types recognized by the server and that the 521 /// message of this type should be processed by the server. 522 /// 523 /// The messages types accepted for processing are: 524 /// - Discover 525 /// - Request 526 /// - Release 527 /// - Decline 528 /// - Inform 529 /// 530 /// @param query Message sent by a client. 531 /// 532 /// @return true if message is accepted for further processing, false 533 /// otherwise. 534 bool acceptMessageType(const Pkt4Ptr& query) const; 535 536 /// @brief Verifies if the server id belongs to our server. 537 /// 538 /// This function checks if the server identifier carried in the specified 539 /// DHCPv4 message belongs to this server. If the server identifier option 540 /// is absent or the value carried by this option is equal to one of the 541 /// server identifiers used by the server, the true is returned. If the 542 /// server identifier option is present, but it doesn't match any server 543 /// identifier used by this server, the false value is returned. 544 /// 545 /// @param pkt DHCPv4 message which server identifier is to be checked. 546 /// 547 /// @return true, if the server identifier is absent or matches one of the 548 /// server identifiers that the server is using; false otherwise. 549 bool acceptServerId(const Pkt4Ptr& pkt) const; 550 //@} 551 552 /// @brief Verifies if specified packet meets RFC requirements 553 /// 554 /// Checks if mandatory option is really there, that forbidden option 555 /// is not there, and that client-id or server-id appears only once. 556 /// 557 /// @param query Pointer to the client's message. 558 /// @param serverid expectation regarding server-id option 559 /// @throw RFCViolation if any issues are detected 560 static void sanityCheck(const Pkt4Ptr& query, RequirementLevel serverid); 561 562 /// @brief Processes incoming DISCOVER and returns response. 563 /// 564 /// Processes received DISCOVER message and verifies that its sender 565 /// should be served. In particular, a lease is selected and sent 566 /// as an offer to a client if it should be served. 567 /// 568 /// @param discover DISCOVER message received from client 569 /// 570 /// @return OFFER message or NULL 571 Pkt4Ptr processDiscover(Pkt4Ptr& discover); 572 573 /// @brief Processes incoming REQUEST and returns REPLY response. 574 /// 575 /// Processes incoming REQUEST message and verifies that its sender 576 /// should be served. In particular, verifies that requested lease 577 /// is valid, not expired, not reserved, not used by other client and 578 /// that requesting client is allowed to use it. 579 /// 580 /// Returns ACK message, NAK message, or NULL 581 /// 582 /// @param request a message received from client 583 /// @param [out] context pointer to the client context where allocated 584 /// and deleted leases are stored. 585 /// 586 /// @return ACK or NAK message 587 Pkt4Ptr processRequest(Pkt4Ptr& request, AllocEngine::ClientContext4Ptr& context); 588 589 /// @brief Processes incoming DHCPRELEASE messages. 590 /// 591 /// In DHCPv4, server does not respond to RELEASE messages, therefore 592 /// this function does not return anything. 593 /// 594 /// @param release message received from client 595 /// @param [out] context pointer to the client context where released 596 /// lease is stored. 597 void processRelease(Pkt4Ptr& release, AllocEngine::ClientContext4Ptr& context); 598 599 /// @brief Process incoming DHCPDECLINE messages. 600 /// 601 /// This method processes incoming DHCPDECLINE. In particular, it extracts 602 /// Requested IP Address option, checks that the address really belongs to 603 /// the client and if it does, calls @ref declineLease. 604 /// 605 /// @param decline message received from client 606 /// @param [out] context pointer to the client context where declined 607 /// lease is stored. 608 void processDecline(Pkt4Ptr& decline, AllocEngine::ClientContext4Ptr& context); 609 610 /// @brief Processes incoming DHCPINFORM messages. 611 /// 612 /// @param inform message received from client 613 /// 614 /// @return DHCPACK to be sent to the client. 615 Pkt4Ptr processInform(Pkt4Ptr& inform); 616 617 /// @brief Build the configured option list 618 /// 619 /// @note The configured option list is an *ordered* list of 620 /// @c CfgOption objects used to append options to the response. 621 /// 622 /// @param ex The exchange where the configured option list is cached 623 void buildCfgOptionList(Dhcpv4Exchange& ex); 624 625 /// @brief Appends options requested by client. 626 /// 627 /// This method assigns options that were requested by client 628 /// (sent in PRL) or are enforced by server. 629 /// 630 /// @param ex The exchange holding both the client's message and the 631 /// server's response. 632 void appendRequestedOptions(Dhcpv4Exchange& ex); 633 634 /// @brief Appends requested vendor options as requested by client. 635 /// 636 /// This method is similar to \ref appendRequestedOptions(), but uses 637 /// vendor options. The major difference is that vendor-options use 638 /// its own option spaces (there may be more than one distinct set of vendor 639 /// options, each with unique vendor-id). Vendor options are requested 640 /// using separate options within their respective vendor-option spaces. 641 /// 642 /// @param ex The exchange holding both the client's message and the 643 /// server's response. 644 void appendRequestedVendorOptions(Dhcpv4Exchange& ex); 645 646 /// @brief Assigns a lease and appends corresponding options 647 /// 648 /// This method chooses the most appropriate lease for requesting 649 /// client and assigning it. Options corresponding to the lease 650 /// are added to specific message. 651 /// 652 /// This method may reset the pointer to the response in the @c ex object 653 /// to indicate that the response should not be sent to the client. 654 /// The caller must check if the response is is null after calling 655 /// this method. 656 /// 657 /// The response type in the @c ex object may be set to DHCPACK or DHCPNAK. 658 /// 659 /// @param ex DHCPv4 exchange holding the client's message to be checked. 660 void assignLease(Dhcpv4Exchange& ex); 661 662 /// @brief Update client name and DNS flags in the lease and response 663 /// 664 /// There are two cases when the client name (FQDN or hostname) and DNS 665 /// flags need to updated after the lease has been allocated: 666 /// 1. If the name is being generated from the lease address 667 /// 2. If the allocation changed the chosen subnet 668 /// 669 /// In the first case this function will generate the name from the 670 /// lease address. In either case, the name and DNS flags are updated 671 /// in the lease and in the response packet. 672 /// 673 /// @param ctx reference to the client context 674 /// @param lease reference to the client lease 675 /// @param query reference to the client query 676 /// @param resp reference to the client response 677 /// @param client_name_changed - true if the new values are already in 678 /// the lease 679 void postAllocateNameUpdate(const AllocEngine::ClientContext4Ptr& ctx, 680 const Lease4Ptr& lease, const Pkt4Ptr& query, 681 const Pkt4Ptr& resp, bool client_name_changed); 682 683 /// @brief Adds the T1 and T2 timers to the outbound response as appropriate 684 /// 685 /// This method determines if either of the timers T1 (option 58) and T2 686 /// (option 59) should be sent to the client. It is influenced by the 687 /// lease's subnet's values for renew-timer, rebind-timer, 688 /// calculate-tee-times, t1-percent, and t2-percent as follows: 689 /// 690 /// By default neither T1 nor T2 will be sent. 691 /// 692 /// T2: 693 /// 694 /// If rebind-timer is set use its value, otherwise if calculate-tee-times 695 /// is true use the value given by valid lease time * t2-percent. Either 696 /// way the value will only be sent if it is less than the valid lease time. 697 /// 698 /// T1: 699 /// 700 /// If renew-timer is set use its value, otherwise if calculate-tee-times 701 /// is true use the value given by valid lease time * t1-percent. Either 702 /// way the value will only be sent if it is less than T2 when T2 is being 703 /// sent, or less than the valid lease time if T2 is not being sent. 704 /// 705 /// @param lease lease being assigned to the client 706 /// @param subnet the subnet to which the lease belongs 707 /// @param resp outbound response for the client to which timers are added. 708 void setTeeTimes(const Lease4Ptr& lease, const Subnet4Ptr& subnet, Pkt4Ptr resp); 709 710 /// @brief Append basic options if they are not present. 711 /// 712 /// This function adds the following basic options if they 713 /// are not yet added to the response message: 714 /// - Subnet Mask, 715 /// - Router, 716 /// - Name Server, 717 /// - Domain Name, 718 /// - Server Identifier. 719 /// 720 /// @param ex DHCPv4 exchange holding the client's message to be checked. 721 void appendBasicOptions(Dhcpv4Exchange& ex); 722 723 /// @brief Sets fixed fields of the outgoing packet. 724 /// 725 /// If the incoming packets belongs to a class and that class defines 726 /// next-server, server-hostname or boot-file-name, we need to set the 727 /// siaddr, sname or filename fields in the outgoing packet. Also, those 728 /// values can be defined for subnet or in reservations. The values 729 /// defined in reservation takes precedence over class values, which 730 /// in turn take precedence over subnet values. 731 /// 732 /// @param ex DHCPv4 exchange holding the client's message and the server's 733 /// response to be adjusted. 734 void setFixedFields(Dhcpv4Exchange& ex); 735 736 /// @brief Processes Client FQDN and Hostname Options sent by a client. 737 /// 738 /// Client may send Client FQDN or Hostname option to communicate its name 739 /// to the server. Server may use this name to perform DNS update for the 740 /// lease being assigned to a client. If server takes responsibility for 741 /// updating DNS for a client it may communicate it by sending the Client 742 /// FQDN or Hostname %Option back to the client. Server select a different 743 /// name than requested by a client to update DNS. In such case, the server 744 /// stores this different name in its response. 745 /// 746 /// Client should not send both Client FQDN and Hostname options. However, 747 /// if client sends both options, server should prefer Client FQDN option 748 /// and ignore the Hostname option. If Client FQDN option is not present, 749 /// the Hostname option is processed. 750 /// 751 /// The Client FQDN %Option is processed by this function as described in 752 /// RFC4702. 753 /// 754 /// In response to a Hostname %Option sent by a client, the server may send 755 /// Hostname option with the same or different hostname. If different 756 /// hostname is sent, it is an indication to the client that server has 757 /// overridden the client's preferred name and will rather use this 758 /// different name to update DNS. However, since Hostname option doesn't 759 /// carry an information whether DNS update will be carried by the server 760 /// or not, the client is responsible for checking whether DNS update 761 /// has been performed. 762 /// 763 /// After successful processing options stored in the first parameter, 764 /// this function may add Client FQDN or Hostname option to the response 765 /// message. In some cases, server may cease to add any options to the 766 /// response, i.e. when server doesn't support DNS updates. 767 /// 768 /// This function does not throw. It simply logs the debug message if the 769 /// processing of the FQDN or Hostname failed. 770 /// 771 /// @param ex The exchange holding both the client's message and the 772 /// server's response. 773 void processClientName(Dhcpv4Exchange& ex); 774 775 /// @brief This function sets statistics related to DHCPv4 packets processing 776 /// to their initial values. 777 /// 778 /// All of the statistics observed by the DHCPv4 server and with the names 779 /// like "pkt4-" are reset to 0. This function must be invoked in the class 780 /// constructor. 781 void setPacketStatisticsDefaults(); 782 783 /// @brief Sets value of the test_send_responses_to_source_ flag. 784 /// 785 /// @param value new value of the test_send_responses_to_source_ flag. setSendResponsesToSource(bool value)786 void setSendResponsesToSource(bool value) { 787 test_send_responses_to_source_ = value; 788 } 789 790 public: 791 792 /// @brief this is a prefix added to the content of vendor-class option 793 /// 794 /// If incoming packet has a vendor class option, its content is 795 /// prepended with this prefix and then interpreted as a class. 796 /// For example, a packet that sends vendor class with value of "FOO" 797 /// will cause the packet to be assigned to class VENDOR_CLASS_FOO. 798 static const std::string VENDOR_CLASS_PREFIX; 799 800 private: 801 /// @brief Process Client FQDN %Option sent by a client. 802 /// 803 /// This function is called by the @c Dhcpv4Srv::processClientName when 804 /// the client has sent the FQDN option in its message to the server. 805 /// It comprises the actual logic to parse the FQDN option and prepare 806 /// the FQDN option to be sent back to the client in the server's 807 /// response. 808 /// 809 /// @param ex The exchange holding both the client's message and the 810 /// server's response. 811 void processClientFqdnOption(Dhcpv4Exchange& ex); 812 813 /// @brief Process Hostname %Option sent by a client. 814 /// 815 /// This method is called by the @c Dhcpv4Srv::processClientName to 816 /// create an instance of the Hostname option to be returned to the 817 /// client. If this instance is created it is included in the response 818 /// message within the @c Dhcpv4Exchange object passed as an argument. 819 /// 820 /// The Hostname option instance is created if the client has included 821 /// Hostname option in its query to the server or if the client has 822 /// included Hostname option code in the Parameter Request List option. 823 /// In the former case, the server can use the Hostname supplied by the 824 /// client or replace it with a new hostname, depending on the server's 825 /// configuration. A reserved hostname takes precedence over a hostname 826 /// supplied by the client or auto generated hostname. 827 /// 828 /// If the 'qualifying-suffix' parameter is specified, its value is used 829 /// to qualify a hostname. For example, if the host reservation contains 830 /// a hostname 'marcin-laptop', and the qualifying suffix is 831 /// 'example.isc.org', the hostname returned to the client will be 832 /// 'marcin-laptop.example.isc.org'. If the 'qualifying-suffix' is not 833 /// specified (empty), the reserved hostname is returned to the client 834 /// unqualified. 835 /// 836 /// The 'qualifying-suffix' value is also used to qualify the hostname 837 /// supplied by the client, when this hostname is unqualified, 838 /// e.g. 'laptop-x'. If the supplied hostname is qualified, e.g. 839 /// 'laptop-x.example.org', the qualifying suffix will not be appended 840 /// to it. 841 /// 842 /// @param ex The exchange holding both the client's message and the 843 /// server's response. 844 void processHostnameOption(Dhcpv4Exchange& ex); 845 846 /// @public 847 /// @brief Marks lease as declined. 848 /// 849 /// This method moves a lease to declined state with all the steps involved: 850 /// - trigger DNS removal (if necessary) 851 /// - disassociate the client information 852 /// - update lease in the database (switch to DECLINED state) 853 /// - increase necessary statistics 854 /// - call lease4_decline hook 855 /// 856 /// @param lease lease to be declined 857 /// @param decline client's message 858 /// @param context reference to a client context 859 void declineLease(const Lease4Ptr& lease, const Pkt4Ptr& decline, 860 AllocEngine::ClientContext4Ptr& context); 861 862 protected: 863 864 /// @brief Creates NameChangeRequests which correspond to the lease 865 /// which has been acquired. 866 /// 867 /// If this function is called when an existing lease is renewed, it 868 /// may generate NameChangeRequest to remove existing DNS entries which 869 /// correspond to the old lease instance. This function may cease to 870 /// generate NameChangeRequests if the notion of the client's FQDN hasn't 871 /// changed between an old and new lease. 872 /// 873 /// @param lease A pointer to the new lease which has been acquired. 874 /// @param old_lease A pointer to the instance of the old lease which has 875 /// @param ddns_params DDNS configuration parameters 876 /// been replaced by the new lease passed in the first argument. The NULL 877 /// value indicates that the new lease has been allocated, rather than 878 /// lease being renewed. 879 void createNameChangeRequests(const Lease4Ptr& lease, 880 const Lease4Ptr& old_lease, 881 const DdnsParams& ddns_params); 882 883 /// @brief Attempts to renew received addresses 884 /// 885 /// Attempts to renew existing lease. This typically includes finding a lease that 886 /// corresponds to the received address. If no such lease is found, a status code 887 /// response is generated. 888 /// 889 /// @param renew client's message asking for renew 890 /// @param reply server's response (ACK or NAK) 891 void renewLease(const Pkt4Ptr& renew, Pkt4Ptr& reply); 892 893 /// @brief Adds server identifier option to the server's response. 894 /// 895 /// This method adds a server identifier to the DHCPv4 message if it doesn't 896 /// exist yet. This is set to the local address on which the client's query has 897 /// been received with the exception of broadcast traffic and DHCPv4o6 query for 898 /// which a socket on the particular interface is found and its address is used 899 /// as server id. 900 /// 901 /// @note This method doesn't throw exceptions by itself but the underlying 902 /// classes being used my throw. The reason for this method to not sanity 903 /// check the specified message is that it is meant to be called internally 904 /// by the @c Dhcpv4Srv class. 905 /// 906 /// @note This method is static because it is not dependent on the class 907 /// state. 908 /// 909 /// @param ex The exchange holding both the client's message and the 910 /// server's response. 911 static void appendServerID(Dhcpv4Exchange& ex); 912 913 /// @brief Check if the relay port RAI sub-option was set in the query. 914 /// 915 /// @param ex The exchange holding the client's message 916 /// @return the port to use to join the relay or 0 for the default 917 static uint16_t checkRelayPort(const Dhcpv4Exchange& ex); 918 919 /// @brief Set IP/UDP and interface parameters for the DHCPv4 response. 920 /// 921 /// This method sets the following parameters for the DHCPv4 message being 922 /// sent to a client: 923 /// - client unicast or a broadcast address, 924 /// - client or relay port, 925 /// - server address, 926 /// - server port, 927 /// - name and index of the interface which is to be used to send the 928 /// message. 929 /// 930 /// Internally it calls the @c Dhcpv4Srv::adjustRemoteAddr to figure 931 /// out the destination address (client unicast address or broadcast 932 /// address). 933 /// 934 /// The destination port is always DHCPv4 client (68) or relay (67) port, 935 /// depending if the response will be sent directly to a client, unless 936 /// a client port was enforced from the command line. 937 /// 938 /// The source port is always set to DHCPv4 server port (67). 939 /// 940 /// The interface selected for the response is always the same as the 941 /// one through which the query has been received. 942 /// 943 /// The source address for the response is the IPv4 address assigned to 944 /// the interface being used to send the response. This function uses 945 /// @c IfaceMgr to get the socket bound to the IPv4 address on the 946 /// particular interface. 947 /// 948 /// @note This method is static because it is not dependent on the class 949 /// state. 950 /// 951 /// @param ex The exchange holding both the client's message and the 952 /// server's response. 953 void adjustIfaceData(Dhcpv4Exchange& ex); 954 955 /// @brief Sets remote addresses for outgoing packet. 956 /// 957 /// This method sets the local and remote addresses on outgoing packet. 958 /// The addresses being set depend on the following conditions: 959 /// - has incoming packet been relayed, 960 /// - is direct response to a client without address supported, 961 /// - type of the outgoing packet, 962 /// - broadcast flag set in the incoming packet. 963 /// 964 /// @warning This method does not check whether provided packet pointers 965 /// are valid. Make sure that pointers are correct before calling this 966 /// function. 967 /// 968 /// @param ex The exchange holding both the client's message and the 969 /// server's response. 970 void adjustRemoteAddr(Dhcpv4Exchange& ex); 971 972 /// @brief converts server-id to text 973 /// Converts content of server-id option to a text representation, e.g. 974 /// "192.0.2.1" 975 /// 976 /// @param opt option that contains server-id 977 /// @return string representation 978 static std::string srvidToString(const OptionPtr& opt); 979 980 /// @brief Selects a subnet for a given client's packet. 981 /// 982 /// If selectSubnet is called to simply do sanity checks (check if a 983 /// subnet would be selected), then there is no need to call hooks, 984 /// as this will happen later (when selectSubnet is called again). 985 /// In such case the sanity_only should be set to true. 986 /// 987 /// @param query client's message 988 /// @param drop if it is true the packet will be dropped 989 /// @param sanity_only if it is true the callout won't be called 990 /// @return selected subnet (or NULL if no suitable subnet was found) 991 isc::dhcp::Subnet4Ptr selectSubnet(const Pkt4Ptr& query, 992 bool& drop, 993 bool sanity_only = false) const; 994 995 /// @brief Selects a subnet for a given client's DHCP4o6 packet. 996 /// 997 /// If selectSubnet is called to simply do sanity checks (check if a 998 /// subnet would be selected), then there is no need to call hooks, 999 /// as this will happen later (when selectSubnet is called again). 1000 /// In such case the sanity_only should be set to true. 1001 /// 1002 /// @param query client's message 1003 /// @param drop if it is true the packet will be dropped 1004 /// @param sanity_only if it is true the callout won't be called 1005 /// @return selected subnet (or NULL if no suitable subnet was found) 1006 isc::dhcp::Subnet4Ptr selectSubnet4o6(const Pkt4Ptr& query, 1007 bool& drop, 1008 bool sanity_only = false) const; 1009 1010 /// @brief dummy wrapper around IfaceMgr::receive4 1011 /// 1012 /// This method is useful for testing purposes, where its replacement 1013 /// simulates reception of a packet. For that purpose it is protected. 1014 virtual Pkt4Ptr receivePacket(int timeout); 1015 1016 /// @brief dummy wrapper around IfaceMgr::send() 1017 /// 1018 /// This method is useful for testing purposes, where its replacement 1019 /// simulates transmission of a packet. For that purpose it is protected. 1020 virtual void sendPacket(const Pkt4Ptr& pkt); 1021 1022 /// @brief Assigns incoming packet to zero or more classes. 1023 /// 1024 /// @note This is done in two phases: first the content of the 1025 /// vendor-class-identifier option is used as a class, by 1026 /// calling @ref classifyByVendor(). Second classification match 1027 /// expressions are evaluated. The resulting classes will be stored 1028 /// in the packet (see @ref isc::dhcp::Pkt4::classes_ and 1029 /// @ref isc::dhcp::Pkt4::inClass). 1030 /// 1031 /// @param pkt packet to be classified 1032 void classifyPacket(const Pkt4Ptr& pkt); 1033 1034 protected: 1035 1036 /// @brief Assigns incoming packet to zero or more classes (required pass). 1037 /// 1038 /// @note This required classification evaluates all classes which 1039 /// were marked for required evaluation. Classes are collected so 1040 /// evaluated in the reversed order than output option processing. 1041 /// 1042 /// @note The only-if-required flag is related because it avoids 1043 /// double evaluation (which is not forbidden). 1044 /// 1045 /// @param ex The exchange holding needed information. 1046 void requiredClassify(Dhcpv4Exchange& ex); 1047 1048 /// @brief Perform deferred option unpacking. 1049 /// 1050 /// @note Options 43 and 224-254 are processed after classification. 1051 /// If a class configures a definition it is applied, if none 1052 /// the global (user) definition is applied. For option 43 1053 /// a last resort definition (same definition as used in previous Kea 1054 /// versions) is applied when none is found. 1055 /// 1056 /// @param query Pointer to the client message. 1057 void deferredUnpack(Pkt4Ptr& query); 1058 1059 /// @brief Executes pkt4_send callout. 1060 /// 1061 /// @param callout_handle pointer to the callout handle. 1062 /// @param query Pointer to a query. 1063 /// @param rsp Pointer to a response. 1064 void processPacketPktSend(hooks::CalloutHandlePtr& callout_handle, 1065 Pkt4Ptr& query, Pkt4Ptr& rsp); 1066 1067 /// @brief Executes buffer4_send callout and sends the response. 1068 /// 1069 /// @param callout_handle pointer to the callout handle. 1070 /// @param rsp pointer to a response. 1071 void processPacketBufferSend(hooks::CalloutHandlePtr& callout_handle, 1072 Pkt4Ptr& rsp); 1073 1074 private: 1075 1076 /// @public 1077 /// @brief Assign class using vendor-class-identifier option 1078 /// 1079 /// @note This is the first part of @ref classifyPacket 1080 /// 1081 /// @param pkt packet to be classified 1082 void classifyByVendor(const Pkt4Ptr& pkt); 1083 1084 /// @private 1085 /// @brief Constructs netmask option based on subnet4 1086 /// @param subnet subnet for which the netmask will be calculated 1087 /// 1088 /// @return Option that contains netmask information 1089 static OptionPtr getNetmaskOption(const Subnet4Ptr& subnet); 1090 1091 protected: 1092 1093 /// UDP port number on which server listens. 1094 uint16_t server_port_; 1095 1096 /// UDP port number to which server sends all responses. 1097 uint16_t client_port_; 1098 1099 /// Indicates if shutdown is in progress. Setting it to true will 1100 /// initiate server shutdown procedure. 1101 volatile bool shutdown_; 1102 1103 /// @brief Allocation Engine. 1104 /// Pointer to the allocation engine that we are currently using 1105 /// It must be a pointer, because we will support changing engines 1106 /// during normal operation (e.g. to use different allocators) 1107 boost::shared_ptr<AllocEngine> alloc_engine_; 1108 1109 /// Should broadcast be enabled on sockets (if true). 1110 bool use_bcast_; 1111 1112 /// @brief Holds information about disabled DHCP service and/or 1113 /// disabled subnet/network scopes. 1114 NetworkStatePtr network_state_; 1115 1116 /// @brief Controls access to the configuration backends. 1117 CBControlDHCPv4Ptr cb_control_; 1118 1119 private: 1120 1121 /// @brief store value that defines if kea will send responses 1122 /// to a source address of incoming packet. Only for testing. 1123 bool test_send_responses_to_source_; 1124 1125 public: 1126 1127 /// Class methods for DHCPv4-over-DHCPv6 handler 1128 1129 /// @brief Updates statistics for received packets 1130 /// @param query packet received 1131 static void processStatsReceived(const Pkt4Ptr& query); 1132 1133 /// @brief Updates statistics for transmitted packets 1134 /// @param response packet transmitted 1135 static void processStatsSent(const Pkt4Ptr& response); 1136 1137 /// @brief Returns the index for "buffer4_receive" hook point 1138 /// @return the index for "buffer4_receive" hook point 1139 static int getHookIndexBuffer4Receive(); 1140 1141 /// @brief Returns the index for "pkt4_receive" hook point 1142 /// @return the index for "pkt4_receive" hook point 1143 static int getHookIndexPkt4Receive(); 1144 1145 /// @brief Returns the index for "subnet4_select" hook point 1146 /// @return the index for "subnet4_select" hook point 1147 static int getHookIndexSubnet4Select(); 1148 1149 /// @brief Returns the index for "lease4_release" hook point 1150 /// @return the index for "lease4_release" hook point 1151 static int getHookIndexLease4Release(); 1152 1153 /// @brief Returns the index for "pkt4_send" hook point 1154 /// @return the index for "pkt4_send" hook point 1155 static int getHookIndexPkt4Send(); 1156 1157 /// @brief Returns the index for "buffer4_send" hook point 1158 /// @return the index for "buffer4_send" hook point 1159 static int getHookIndexBuffer4Send(); 1160 1161 /// @brief Returns the index for "lease4_decline" hook point 1162 /// @return the index for "lease4_decline" hook point 1163 static int getHookIndexLease4Decline(); 1164 1165 /// @brief Return a list of all paths that contain passwords or secrets for 1166 /// kea-dhcp4. 1167 /// 1168 /// @return the list of lists of sequential JSON map keys needed to reach 1169 /// the passwords and secrets. 1170 std::list<std::list<std::string>> jsonPathsToRedact() const final override; 1171 }; 1172 1173 } // namespace dhcp 1174 } // namespace isc 1175 1176 #endif // DHCP4_SRV_H 1177