1 // Copyright (C) 2014-2020 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 DHCP6_CLIENT_H 8 #define DHCP6_CLIENT_H 9 10 #include <asiolink/io_address.h> 11 #include <dhcp/duid.h> 12 #include <dhcp/option.h> 13 #include <dhcp/option6_client_fqdn.h> 14 #include <dhcpsrv/lease.h> 15 #include <dhcp6/tests/dhcp6_test_utils.h> 16 #include <util/staged_value.h> 17 #include <boost/noncopyable.hpp> 18 #include <boost/shared_ptr.hpp> 19 #include <list> 20 #include <set> 21 #include <vector> 22 23 namespace isc { 24 namespace dhcp { 25 namespace test { 26 27 /// @brief DHCPv6 client used for unit testing. 28 /// 29 /// This class implements a DHCPv6 "client" which interoperates with the 30 /// @c NakedDhcpv6Srv class. It calls @c NakedDhcpv6Srv::fakeReceive to 31 /// deliver client messages to the server for processing. The server places 32 /// the response in the @c NakedDhcpv6Srv::fake_sent_ container. The client 33 /// pops messages from this container which simulates reception of the 34 /// response from the server. 35 /// 36 /// The client maintains the leases it acquired from the server. If it has 37 /// acquired the lease as a result of SARR exchange, it will use this lease 38 /// when the Rebind process is triggered by the unit test. 39 /// 40 /// The client exposes a set of functions which simulate different exchange 41 /// types between the client and the server. It also provides the access to 42 /// the objects encapsulating responses from the server so as it is possible 43 /// to verify from the unit test that the server's response is correct. 44 /// 45 /// @todo This class has been implemented to simplify the structure of the 46 /// unit test and to make unit tests code self-explanatory. Currently, 47 /// this class is mostly used by the unit tests which test Rebind processing 48 /// logic. At some point we may want to use this class to test some other 49 /// message types, e.g. Renew, in which case it may need to be extended. 50 /// Also, once we implement the support for multiple IAAddr and IAPrefix 51 /// options within single IA, the logic which maintains leases will have 52 /// to be extended to support it. 53 class Dhcp6Client : public boost::noncopyable { 54 public: 55 56 /// @brief Holds an information about single lease. 57 struct LeaseInfo { 58 /// @brief A structure describing the lease. 59 Lease6 lease_; 60 61 /// @brief Holds the last status code that server has sent for 62 /// the particular lease. 63 uint16_t status_code_; 64 65 /// @brief Default constructor for the structure. LeaseInfoLeaseInfo66 LeaseInfo() : 67 lease_(), status_code_(0) { } 68 69 /// @brief Constructor which sets the lease type. 70 /// 71 /// @param lease_type One of the D6O_IA_NA or D6O_IA_PD. LeaseInfoLeaseInfo72 LeaseInfo(const uint16_t lease_type) : 73 lease_(), status_code_(0) { 74 lease_.type_ = lease_type == D6O_IA_NA ? Lease::TYPE_NA : 75 Lease::TYPE_PD; 76 } 77 }; 78 79 /// @brief Holds the current client configuration obtained from the 80 /// server over DHCP. 81 /// 82 /// Currently it simply contains the collection of leases acquired 83 /// and a list of options. Note: this is a simple copy of all 84 /// non-IA options and often includes "protocol" options, like 85 /// server-id and client-id. 86 struct Configuration { 87 /// @brief List of received leases 88 std::vector<Lease6> leases_; 89 90 /// @brief A map of IAID, status code tuples. 91 std::map<uint32_t, uint16_t> status_codes_; 92 93 /// @brief List of received options 94 OptionCollection options_; 95 96 /// @brief Status code received in the global option scope. 97 uint16_t status_code_; 98 99 /// @brief Indicates if the status code has been received in the 100 /// last transaction. 101 bool received_status_code_; 102 103 /// @brief Constructor. ConfigurationConfiguration104 Configuration() { 105 clear(); 106 } 107 108 /// @brief Clears configuration. clearConfiguration109 void clear() { 110 leases_.clear(); 111 status_codes_.clear(); 112 resetGlobalStatusCode(); 113 options_.clear(); 114 } 115 116 /// @brief Clears global status code. 117 /// 118 /// This function should be called before the new message is received. resetGlobalStatusCodeConfiguration119 void resetGlobalStatusCode() { 120 status_code_ = 0; 121 received_status_code_ = false; 122 } 123 124 /// @brief Finds an option with the specific code in the received 125 /// configuration. 126 /// 127 /// @param code Option code. 128 /// 129 /// @return Pointer to the option if the option exists, or NULL if 130 /// the option doesn't exist. findOptionConfiguration131 OptionPtr findOption(const uint16_t code) const { 132 std::multimap<unsigned int, OptionPtr>::const_iterator it = options_.find(code); 133 if (it != options_.end()) { 134 return (it->second); 135 } 136 return (OptionPtr()); 137 } 138 }; 139 140 /// @brief Holds the DHCPv6 messages taking part in transaction between 141 /// the client and the server. 142 struct Context { 143 /// @brief Holds the last sent message from the client to the server. 144 Pkt6Ptr query_; 145 /// @brief Holds the last sent message by the server to the client. 146 Pkt6Ptr response_; 147 }; 148 149 /// @brief Structure holding information to be placed in client's IA. 150 struct ClientIA { 151 Lease::Type type_; ///< IA type 152 uint32_t iaid_; ///< IAID 153 asiolink::IOAddress prefix_; ///< prefix or address 154 uint8_t prefix_len_; ///< prefix length 155 156 /// @brief Constructor. 157 /// 158 /// @param type IA type. 159 /// @param iaid IAID. 160 /// @param prefix Address or prefix. 161 /// @param prefix_len Prefix length. ClientIAClientIA162 ClientIA(const Lease::Type& type, const uint32_t iaid, 163 const asiolink::IOAddress& prefix, 164 const uint8_t prefix_len) 165 : type_(type), iaid_(iaid), prefix_(prefix), 166 prefix_len_(prefix_len) { 167 } 168 }; 169 170 /// @brief Creates a new client. 171 /// 172 /// This constructor initializes the class members to default values: 173 /// - relay link-addr = 3000:1::1 174 /// - first transaction id = 0 175 /// - dest-addr = All_DHCP_Relay_Agents_and_Servers 176 /// - duid (LLT) = <random 4 bytes>00010203040506 177 /// - link-local-addr = fe80::3a60:77ff:fed5:cdef 178 /// - IA_NA not requested 179 /// - IA_PD not requested 180 /// - not relayed 181 Dhcp6Client(); 182 183 /// @brief Creates a new client that communicates with a specified server. 184 /// 185 /// This constructor allows passing a pointer to the server object which 186 /// should be used in a test. The server may be preconfigured before passed 187 /// to the constructor. The default configuration used by the client is: 188 /// - relay link-addr = 3000:1::1 189 /// - first transaction id = 0 190 /// - dest-addr = All_DHCP_Relay_Agents_and_Servers 191 /// - duid (LLT) = <random 4 bytes>00010203040506 192 /// - link-local-addr = fe80::3a60:77ff:fed5:cdef 193 /// - IA_NA not requested 194 /// - IA_PD not requested 195 /// - not relayed 196 /// 197 /// @param srv Object representing server under test. 198 Dhcp6Client(boost::shared_ptr<isc::dhcp::test::NakedDhcpv6Srv>& srv); 199 200 /// @brief Create lease for the client. 201 /// 202 /// This function creates new lease on the client side without contacting 203 /// the server. This may be useful for the negative tests in which the 204 /// client is supposed to send invalid addresses/prefixes to the server 205 /// and expect certain responses. 206 /// 207 /// @param lease A lease to be applied for the client. 208 void createLease(const Lease6& lease); 209 210 /// @brief Performs a 4-way exchange between the client and the server. 211 /// 212 /// If the 4-way exchange is successful, the client should acquire leases 213 /// according to the server's current configuration and the type of leases 214 /// that have been requested (IA_NA, IA_PD). 215 /// 216 /// The leases acquired are accessible through the @c config_ member. 217 /// 218 /// @throw This function doesn't throw exceptions on its own, but it calls 219 /// functions that are not exception safe, so it may throw exceptions if 220 /// error occurs. 221 /// 222 /// @todo Perform sanity checks on returned messages. 223 void doSARR(); 224 225 /// @brief Send Solicit and receive Advertise. 226 /// 227 /// This function simulates the first transaction of the 4-way exchange, 228 /// i.e. sends a Solicit to the server and receives Advertise. It doesn't 229 /// set the lease configuration in the @c config_. 230 /// 231 /// @param always_apply_config Apply received configuration even if the 232 /// Advertise message is received. Default value is false. 233 /// 234 /// @throw This function doesn't throw exceptions on its own, but it calls 235 /// functions that are not exception safe, so it may throw exceptions if 236 /// error occurs. 237 /// 238 /// @todo Perform sanity checks on returned messages. 239 void doSolicit(const bool always_apply_config = false); 240 241 /// @brief Sends a Renew to the server and receives the Reply. 242 /// 243 /// This function simulates sending the Renew message to the server and 244 /// receiving server's response (if any). The client uses existing leases 245 /// (either address or prefixes) and places them in the Renew message. 246 /// If the server responds to the Renew (and extends the lease lifetimes) 247 /// the current lease configuration is updated. 248 /// 249 /// @throw This function doesn't throw exceptions on its own, but it calls 250 /// functions that are not exception safe, so it may throw exceptions if 251 /// error occurs. 252 /// 253 /// @todo Perform sanity checks on returned messages. 254 void doRenew(); 255 256 /// @brief Sends a Rebind to the server and receives the Reply. 257 /// 258 /// This function simulates sending the Rebind message to the server and 259 /// receiving server's response (if any). The client uses existing leases 260 /// (either address or prefixes) and places them in the Rebind message. 261 /// If the server responds to the Rebind (and extends the lease lifetimes) 262 /// the current lease configuration is updated. 263 /// 264 /// @throw This function doesn't throw exceptions on its own, but it calls 265 /// functions that are not exception safe, so it may throw exceptions if 266 /// error occurs. 267 /// 268 /// @todo Perform sanity checks on returned messages. 269 void doRebind(); 270 271 /// @brief Sends Request to the server and receives Reply. 272 /// 273 /// This function simulates sending the Request message to the server and 274 /// receiving server's response (if any). The client copies IA options 275 /// from the current context (server's Advertise) to request acquisition 276 /// of offered IAs. If the server responds to the Request (leases are 277 /// acquired) the client's lease configuration is updated. 278 /// 279 /// @throw This function doesn't throw exceptions on its own, but it calls 280 /// functions that are not exception safe, so it may throw exceptions if 281 /// error occurs. 282 /// 283 /// @todo Perform sanity checks on returned messages. 284 void doRequest(); 285 286 /// @brief Sends Confirm to the server and receives Reply. 287 /// 288 /// This function simulates sending the Confirm message to the server and 289 /// receiving server's response (if any). 290 void doConfirm(); 291 292 /// @brief Sends Decline to the server and receives Reply. 293 /// 294 /// This function simulates sending the Decline message to the server and 295 /// receiving the server's response. 296 /// @param include_address should the address be included? 297 void doDecline(const bool include_address = true); 298 299 /// @brief Performs stateless (inf-request / reply) exchange. 300 /// 301 /// This function generates Information-request message, sends it 302 /// to the server and then receives the reply. Contents of the Inf-Request 303 /// are controlled by client_ias_, use_client_id_ and use_oro_ 304 /// fields. This method does not process the response in any specific 305 /// way, just stores it. 306 void doInfRequest(); 307 308 /// @brief Sends Release to the server. 309 /// 310 /// This function simulates sending the Release message to the server 311 /// and receiving server's response. 312 void doRelease(); 313 314 /// @brief Removes the stateful configuration obtained from the server. 315 /// 316 /// It removes all leases held by the client. clearConfig()317 void clearConfig() { 318 config_.clear(); 319 } 320 321 /// @brief Simulates aging of leases by the specified number of seconds. 322 /// 323 /// This function moves back the time of acquired leases by the specified 324 /// number of seconds. It is useful for checking whether the particular 325 /// lease has been later updated (e.g. as a result of Rebind) as it is 326 /// expected that the fresh lease has cltt set to "now" (not to the time 327 /// in the past). 328 /// 329 /// @param secs Number of seconds by which the time should be moved. 330 /// @param update_server Indicates if the leases should be updated on the 331 /// server. 332 void fastFwdTime(const uint32_t secs, const bool update_server = false); 333 334 /// @brief Returns DUID option used by the client. 335 OptionPtr getClientId() const; 336 337 /// @brief Returns current context. getContext()338 const Context& getContext() const { 339 return (context_); 340 } 341 342 /// @brief Returns the collection of IAIDs held by the client. 343 std::set<uint32_t> getIAIDs() const; 344 345 /// @brief Returns lease at specified index. 346 /// 347 /// @warning This method doesn't check if the specified index is out of 348 /// range. The caller is responsible for using a correct offset by 349 /// invoking the @c getLeaseNum function. 350 /// 351 /// @param at Index of the lease held by the client. 352 /// @return A lease at the specified index. getLease(const size_t at)353 Lease6 getLease(const size_t at) const { 354 return (config_.leases_[at]); 355 } 356 357 /// @brief Returns collection of leases for specified IAID. 358 /// 359 /// @param iaid IAID for which the leases should be returned. 360 /// 361 /// @return Vector containing leases for the IAID. 362 std::vector<Lease6> getLeasesByIAID(const uint32_t iaid) const; 363 364 /// @brief Returns collection of leases by type. 365 /// 366 /// @param type Lease type: D6O_IA_NA or D6O_IA_PD. 367 /// 368 /// @return Vector containing leases of the specified type. 369 std::vector<Lease6> getLeasesByType(const Lease::Type& lease_type) const; 370 371 /// @brief Returns leases with non-zero lifetimes. 372 std::vector<Lease6> getLeasesWithNonZeroLifetime() const; 373 374 /// @brief Returns leases with zero lifetimes. 375 std::vector<Lease6> getLeasesWithZeroLifetime() const; 376 377 /// @brief Returns leases by lease address/prefix. 378 /// 379 /// @param address Leased address. 380 /// 381 /// @return Vector containing leases for the specified address. 382 std::vector<Lease6> 383 getLeasesByAddress(const asiolink::IOAddress& address) const; 384 385 /// @brief Returns leases belonging to specified address range. 386 /// 387 /// @param first Lower bound of the address range. 388 /// @param second Upper bound of the address range. 389 /// 390 /// @return Vector containing leases belonging to specified address range. 391 std::vector<Lease6> 392 getLeasesByAddressRange(const asiolink::IOAddress& first, 393 const asiolink::IOAddress& second) const; 394 395 /// @brief Returns leases belonging to prefix pool. 396 /// 397 /// @param prefix Prefix of the pool. 398 /// @param prefix_len Prefix length. 399 /// @param delegated_len Delegated prefix length. 400 /// 401 /// @return Vector containing leases belonging to specified prefix pool. 402 std::vector<Lease6> 403 getLeasesByPrefixPool(const asiolink::IOAddress& prefix, 404 const uint8_t prefix_len, 405 const uint8_t delegated_len) const; 406 407 /// @brief Checks if client has lease for the specified address. 408 /// 409 /// @param address Address for which lease should be found. 410 /// 411 /// @return true if client has lease for the address, false otherwise. 412 bool hasLeaseForAddress(const asiolink::IOAddress& address) const; 413 414 /// @brief Checks if client has lease for the specified address in the 415 /// IA_NA identified by IAID. 416 /// 417 /// @param address Address for which lease should be found. 418 /// @param iaid IAID of the IA_NA in which the lease is expected. 419 bool hasLeaseForAddress(const asiolink::IOAddress& address, 420 const IAID& iaid) const; 421 422 /// @brief Checks if client has a lease for an address within range. 423 /// 424 /// @param first Lower bound of the address range. 425 /// @param last Upper bound of the address range. 426 /// 427 /// @return true if client has lease for the address within the range, 428 /// false otherwise. 429 bool hasLeaseForAddressRange(const asiolink::IOAddress& first, 430 const asiolink::IOAddress& last) const; 431 432 /// @brief Checks if client has a lease with zero lifetimes for the 433 /// specified address. 434 /// 435 /// @param address Address for which lease should be found. 436 /// 437 /// @return true if client has a lease, false otherwise. 438 bool hasLeaseWithZeroLifetimeForAddress(const asiolink::IOAddress& address) const; 439 440 /// @brief Checks if client has a lease for a prefix. 441 /// 442 /// @param prefix Prefix. 443 /// @param prefix_len Prefix length. 444 /// 445 /// @return true if client has a lease for the specified prefix, false 446 /// otherwise. 447 bool hasLeaseForPrefix(const asiolink::IOAddress& prefix, 448 const uint8_t prefix_len) const; 449 450 /// @brief Checks if client as a lease for prefix in the IA_PD identified 451 /// by specified IAID. 452 /// 453 /// @param prefix Prefix. 454 /// @param prefix_len Prefix length. 455 /// @param iaid IAID of the IA_PD in which the lease is expected. 456 bool hasLeaseForPrefix(const asiolink::IOAddress& prefix, 457 const uint8_t prefix_len, 458 const IAID& iaid) const; 459 460 /// @brief Checks if client has a lease belonging to a prefix pool. 461 /// 462 /// @param prefix Pool prefix. 463 /// @param prefix_len Prefix length. 464 /// @param delegated_len Delegated prefix length. 465 /// 466 /// @return true if client has a lease belonging to specified pool, 467 /// false otherwise. 468 bool hasLeaseForPrefixPool(const asiolink::IOAddress& prefix, 469 const uint8_t prefix_len, 470 const uint8_t delegated_len) const; 471 472 /// @brief Checks if client has a lease with zero lifetimes for a prefix. 473 /// 474 /// @param prefix Prefix. 475 /// @param prefix_len Prefix length. 476 /// 477 /// @return true if client has a lease with zero lifetimes for a prefix. 478 bool hasLeaseWithZeroLifetimeForPrefix(const asiolink::IOAddress& prefix, 479 const uint8_t prefix_len) const; 480 481 /// @brief Checks that specified option exists and contains a desired 482 /// address. 483 /// 484 /// The option must cast to the @ref Option6AddrLst type. The function 485 /// expects that this option contains at least one address and checks 486 /// first address for equality with @ref expected_address. 487 /// 488 /// @param option_type Option type. 489 /// @param expected_address Desired address. 490 /// @param config Configuration obtained from the server. 491 bool hasOptionWithAddress(const uint16_t option_type, 492 const std::string& expected_address) const; 493 494 /// @brief Returns the value of the global status code for the last 495 /// transaction. getStatusCode()496 uint16_t getStatusCode() const { 497 return (config_.status_code_); 498 } 499 500 /// @brief Returns status code set by the server for the IAID. 501 /// 502 /// @param iaid for which the status is desired 503 /// @return A status code for the given iaid 504 uint16_t getStatusCode(const uint32_t iaid) const; 505 506 /// @brief Returns T1 and T2 timers associated with a given iaid 507 /// 508 /// Changed to get the T1 an T2 times from acquired leases to 509 /// IA options. 510 /// 511 /// @param iaid iaid of the target IA 512 /// @param[out] t1 set to the value of the IA's T1 513 /// @param[out] t2 set to the value of the IA's T2 514 /// @return true if there is an IA option for the given iaid 515 bool getTeeTimes(const uint32_t iaid, uint32_t& t1, uint32_t& t2) const; 516 517 /// @brief Returns number of acquired leases. getLeaseNum()518 size_t getLeaseNum() const { 519 return (config_.leases_.size()); 520 } 521 522 /// @brief Returns the server that the client is communicating with. getServer()523 boost::shared_ptr<isc::dhcp::test::NakedDhcpv6Srv>& getServer() { 524 return (srv_); 525 } 526 527 /// @brief Sets the client's DUID from a string value 528 /// 529 /// Replaces the client's DUID with one constructed from the given 530 /// string. The string is expected to contain hexadecimal digits with or 531 /// without ":" separators. 532 /// 533 /// @param str The string of digits from which to create the DUID 534 /// 535 /// The DUID modification affects the value returned by the 536 /// @c Dhcp6Client::getClientId 537 void setDUID(const std::string& duid_str); 538 539 /// @brief Modifies the client's DUID (adds one to it). 540 /// 541 /// The DUID should be modified to test negative scenarios when the client 542 /// acquires a lease and tries to renew it with a different DUID. The server 543 /// should detect the DUID mismatch and react accordingly. 544 /// 545 /// The DUID modification affects the value returned by the 546 /// @c Dhcp6Client::getClientId 547 void modifyDUID(); 548 549 /// @brief Checks if the global status code was received in the response 550 /// from the server. 551 /// 552 /// @return true if the global status code option was received. receivedStatusCode()553 bool receivedStatusCode() const { 554 return (config_.received_status_code_); 555 } 556 557 /// @brief Sets destination address for the messages being sent by the 558 /// client. 559 /// 560 /// By default, the client uses All_DHCP_Relay_Agents_and_Servers 561 /// multicast address to communicate with the server. In certain cases 562 /// it may be desired that different address is used (e.g. unicast in Renew). 563 /// This function sets the new address for all future exchanges with the 564 /// server. 565 /// 566 /// @param dest_addr New destination address. setDestAddress(const asiolink::IOAddress & dest_addr)567 void setDestAddress(const asiolink::IOAddress& dest_addr) { 568 dest_addr_ = dest_addr; 569 } 570 571 /// @brief Sets the interface to be used by the client. 572 /// 573 /// @param iface_name Interface name. setInterface(const std::string & iface_name)574 void setInterface(const std::string& iface_name) { 575 iface_name_ = iface_name; 576 } 577 578 /// @brief Sets the interface to be used by the client. 579 /// 580 /// @param iface_index Interface index. setIfaceIndex(uint32_t iface_index)581 void setIfaceIndex(uint32_t iface_index) { 582 iface_index_ = iface_index; 583 } 584 585 /// @brief Sets link local address used by the client. 586 /// 587 /// @param link_local New link local address. setLinkLocal(const asiolink::IOAddress & link_local)588 void setLinkLocal(const asiolink::IOAddress& link_local) { 589 link_local_ = link_local; 590 } 591 592 /// @brief Specifies address to be included in client's message. 593 /// 594 /// This method specifies IPv6 address to be included within IA_NA 595 /// option sent by the client. In order to specify multiple addresses 596 /// to be included in a particular IA_NA, this method must be called 597 /// multiple times to specify each address separately. In such case, 598 /// the value of the IAID should remain the same across all calls to 599 /// this method. 600 /// 601 /// This method is typically called to specify IA_NA options to be 602 /// sent to the server during 4-way handshakes and during lease 603 /// renewal to request allocation of new leases (as per RFC 8415). 604 /// 605 /// @param iaid IAID. 606 /// @param address IPv6 address to be included in the IA_NA. It defaults 607 /// to IPv6 zero address, which indicates that no address should be 608 /// included in the IA_NA (empty IA_NA will be sent). 609 void requestAddress(const uint32_t iaid = 1234, 610 const asiolink::IOAddress& address = 611 asiolink::IOAddress::IPV6_ZERO_ADDRESS()); 612 613 /// @brief Specifies IPv6 prefix to be included in client's message. 614 /// 615 /// This method specifies IPv6 prefix to be included within IA_PD 616 /// option sent by the client. In order to specify multiple prefixes 617 /// to be included in a particular IA_PD, this method must be called 618 /// multiple times to specify each prefix separately. In such case, 619 /// the value of the IAID should remain the same across all calls to 620 /// this method. 621 /// 622 /// This method is typically called to specify IA_PD options to be 623 /// sent to the server during 4-way handshakes and during lease 624 /// renewal to request allocation of new leases (as per RFC 8415). 625 /// 626 /// @param iaid IAID. 627 /// @param prefix_len Prefix length. 628 /// @param prefix Prefix to be included. This value defaults to the 629 /// IPv6 zero address. If zero address is specified and prefix_len is 630 /// set to 0, the IA Prefix option will not be included in the IA_PD. 631 /// If the prefix_len is non-zero and the prefix is IPv6 zero address 632 /// the prefix length hint will be included in the IA Prefix option. 633 void requestPrefix(const uint32_t iaid = 5678, 634 const uint8_t prefix_len = 0, 635 const asiolink::IOAddress& prefix = 636 asiolink::IOAddress::IPV6_ZERO_ADDRESS()); 637 638 /// @brief Removes IAs specified by @ref requestAddress and 639 /// @ref requestPrefix methods. 640 /// 641 /// If this method is called and the client initiates an exchange with 642 /// a server the client will only include IAs for which it has leases. 643 /// If the client has no leases (e.g. a Solicit case), no IAs will be 644 /// included in the client's message. clearRequestedIAs()645 void clearRequestedIAs() { 646 client_ias_.clear(); 647 } 648 649 /// @brief Simulate sending messages through a relay. 650 /// 651 /// @param use Parameter which 'true' value indicates that client should 652 /// simulate sending messages via relay. 653 /// @param link_addr Relay link-addr. 654 void useRelay(const bool use = true, 655 const asiolink::IOAddress& link_addr = asiolink::IOAddress("3000:1::1")) { 656 use_relay_ = use; 657 relay_link_addr_ = link_addr; 658 } 659 660 /// @brief Sets interface id value to be inserted into relay agent option. 661 /// 662 /// @param interface_id Value of the interface id as string. 663 void useInterfaceId(const std::string& interface_id); 664 665 /// @brief Controls whether the client should send a client-id or not 666 /// @param send should the client-id be sent? useClientId(const bool send)667 void useClientId(const bool send) { 668 use_client_id_ = send; 669 } 670 671 /// @brief Specifies if the Rapid Commit option should be included in 672 /// the Solicit message. 673 /// 674 /// @param rapid_commit Boolean parameter controlling if the Rapid Commit 675 /// option must be included in the Solicit (if true), or not (if false). useRapidCommit(const bool rapid_commit)676 void useRapidCommit(const bool rapid_commit) { 677 use_rapid_commit_ = rapid_commit; 678 } 679 680 /// @brief Specifies server-id to be used in send messages 681 /// 682 /// Overrides the server-id to be sent when server-id is expected to be 683 /// sent. May be NULL, which means use proper server-id sent in Advertise 684 /// (which is a normal client behavior). 685 /// 686 /// @param server_id server-id to be sent useServerId(const OptionPtr & server_id)687 void useServerId(const OptionPtr& server_id) { 688 forced_server_id_ = server_id; 689 } 690 691 /// @brief Creates an instance of the Client FQDN option to be included 692 /// in the client's message. 693 /// 694 /// @param flags Flags. 695 /// @param fqdn_name Name in the textual format. 696 /// @param fqdn_type Type of the name (fully qualified or partial). 697 void useFQDN(const uint8_t flags, const std::string& fqdn_name, 698 Option6ClientFqdn::DomainNameType fqdn_type); 699 700 /// @brief Lease configuration obtained by the client. 701 Configuration config_; 702 703 /// @brief Link address of the relay to be used for relayed messages. 704 asiolink::IOAddress relay_link_addr_; 705 706 /// @brief RelayInfo (information about relays) 707 /// 708 /// Dhcp6Client will typically construct this info itself, but if 709 /// it is provided here by the test, this data will be used as is. 710 std::vector<Pkt6::RelayInfo> relay_info_; 711 712 /// @brief Controls whether the client will send ORO 713 /// 714 /// The actual content of the ORO is specified in oro_. 715 /// It is useful to split the actual content and the ORO sending 716 /// decision, so we could test cases of sending empty ORO. 717 /// @param send controls whether ORO will be sent or not. useORO(bool send)718 void useORO(bool send) { 719 use_oro_ = send; 720 } 721 722 /// @brief Instructs client to request specified option in ORO 723 /// 724 /// @param option_code client will request this option code requestOption(uint16_t option_code)725 void requestOption(uint16_t option_code) { 726 use_oro_ = true; 727 oro_.push_back(option_code); 728 } 729 730 /// @brief Controls whether the client will send DOCSIS vendor ORO 731 /// 732 /// The actual content of the ORO is specified in docsis_oro_. 733 /// It is useful to split the actual content and the ORO sending 734 /// decision, so we could test cases of sending empty ORO. 735 /// @param send controls whether ORO will be sent or not. useDocsisORO(bool send)736 void useDocsisORO(bool send) { 737 use_docsis_oro_ = send; 738 } 739 740 /// @brief Instructs client to request specified option in DOCSIS 741 /// vendor ORO 742 /// 743 /// @param option_code client will request this option code requestDocsisOption(uint16_t option_code)744 void requestDocsisOption(uint16_t option_code) { 745 use_docsis_oro_ = true; 746 docsis_oro_.push_back(option_code); 747 } 748 749 /// @brief returns client-id 750 /// @return client-id getDuid()751 DuidPtr getDuid() const { 752 return (duid_); 753 } 754 755 /// @brief Generates IA_NA based on lease information 756 /// 757 /// @param query generated IA_NA options will be added here 758 /// @param include_address should the address be included? 759 void generateIAFromLeases(const Pkt6Ptr& query, 760 const bool include_address = true); 761 762 /// @brief Adds extra option (an option the client will always send) 763 /// 764 /// @param opt additional option to be sent 765 void addExtraOption(const OptionPtr& opt); 766 767 /// @brief Configures the client to not send any extra options. 768 void clearExtraOptions(); 769 770 /// @brief Add a client class. 771 /// 772 /// @param client_class name of the class to be added. 773 void addClass(const ClientClass& client_class); 774 775 /// @brief Configures the client to not add client classes. 776 void clearClasses(); 777 778 /// @brief Debugging method the prints currently held configuration 779 /// 780 /// @todo: This is mostly useful when debugging tests. This method 781 /// is incomplete. Please extend it when needed. 782 void printConfiguration() const; 783 784 /// @brief Receives a response from the server. 785 /// 786 /// This method is useful to receive response from the server after 787 /// parking a packet. In this case, the packet is not received as a 788 /// result of initial exchange, e.g. @c doRequest. The test can call 789 /// this method to complete the transaction when it expects that the 790 /// packet has been unparked. 791 void receiveResponse(); 792 793 private: 794 795 /// @brief Applies the new leases for the client. 796 /// 797 /// This method is called when the client obtains a new configuration 798 /// from the server in the Reply message. This function adds new leases 799 /// or replaces existing ones, on the client's side. Client uses these 800 /// leases in any later communication with the server when doing Renew 801 /// or Rebind. 802 /// 803 /// @param reply Server response. 804 /// @param state specifies lease state (see Lease::STATE_* for details). 805 /// 806 /// The default for state is 0. We could have included dhcpsrv/lease.h 807 /// and used Lease::STATE_DEFAULT, but that would complicate the header 808 /// inclusion dependencies. It's easier to simply use 0 as the default. 809 /// 810 /// @todo Currently this function supports one IAAddr or IAPrefix option 811 /// within IA. We will need to extend it to support multiple options 812 /// within a single IA once server supports that. 813 void applyRcvdConfiguration(const Pkt6Ptr& reply, uint32_t state = 0); 814 815 /// @brief Applies configuration for the single lease. 816 /// 817 /// This method is called by the @c Dhcp6Client::applyRcvdConfiguration for 818 /// each individual lease. 819 /// 820 /// @param lease_info Structure holding new lease information. 821 void applyLease(const Lease6& lease); 822 823 /// @brief Includes Client FQDN in the client's message. 824 /// 825 /// This method checks if @c fqdn_ is specified and includes it in 826 /// the client's message. 827 void appendFQDN(); 828 829 /// @brief Includes IAs to be requested. 830 /// 831 /// This method includes IAs explicitly requested using client_ias_ 832 /// 833 /// @param query Pointer to the client's message to which IAs should be 834 /// added. 835 void appendRequestedIAs(const Pkt6Ptr& query) const; 836 837 /// @brief Copy IA options from one message to another. 838 /// 839 /// This method copies IA_NA and IA_PD options from one message to another. 840 /// It is useful when the client needs to construct the Request message 841 /// using addresses and prefixes returned by the client in Advertise. 842 /// 843 /// @param source Message from which IA options will be copied. 844 /// @param dest Message to which IA options will be copied. 845 /// 846 /// @todo Add support for IA_TA. 847 void copyIAs(const Pkt6Ptr& source, const Pkt6Ptr& dest); 848 849 /// @brief Creates IA options from existing configuration. 850 /// 851 /// This method iterates over existing leases that client acquired and 852 /// places corresponding IA_NA or IA_PD options into a specified message. 853 /// This is useful to construct Renew, Rebind or Confirm message from the 854 /// existing configuration that client has obtained using 4-way exchange. 855 /// 856 /// If there are no leases no IA options will be added. If the lease exists 857 /// but any of the lifetime values is set to 0, the IA option will be added 858 /// but the IAAddr (or IAPrefix) option will not be added. 859 /// 860 /// @param dest Message to which the IA options will be added. 861 void copyIAsFromLeases(const Pkt6Ptr& dest) const; 862 863 /// @brief Creates client's side DHCP message. 864 /// 865 /// @param msg_type Type of the message to be created. 866 /// @return An instance of the message created. 867 Pkt6Ptr createMsg(const uint8_t msg_type); 868 869 /// @brief Generates DUID for the client. 870 /// 871 /// @param duid_type Type of the DUID. Currently, only LLT is accepted. 872 /// @return Object encapsulating a DUID. 873 DuidPtr generateDUID(DUID::DUIDType duid_type) const; 874 875 /// @brief Returns client's leases which match the specified condition. 876 /// 877 /// @param property A value of the lease property used to search the lease. 878 /// @param equals A flag which indicates if the operator should search 879 /// for the leases which property is equal to the value of @c property 880 /// parameter (if true), or unequal (if false). 881 /// @param [out] leases A vector in which the operator will store leases 882 /// found. 883 /// 884 /// @tparam BaseType Base type to which the property belongs: @c Lease or 885 /// @c Lease6. 886 /// @tparam PropertyType A type of the property, e.g. @c uint32_t for IAID. 887 /// @tparam MemberPointer A pointer to the member, e.g. @c &Lease6::iaid_. 888 template<typename BaseType, typename PropertyType, 889 PropertyType BaseType::*MemberPointer> 890 void getLeasesByProperty(const PropertyType& property, const bool equals, 891 std::vector<Lease6>& leases) const; 892 893 /// @brief Simulates reception of the message from the server. 894 /// 895 /// @return Received message. 896 Pkt6Ptr receiveOneMsg(); 897 898 /// @brief Simulates sending a message to the server. 899 /// 900 /// This function instantly triggers processing of the message by the 901 /// server. The server's response can be gathered by invoking the 902 /// @c receiveOneMsg function. 903 /// 904 /// @param msg Message to be sent. 905 void sendMsg(const Pkt6Ptr& msg); 906 907 /// @brief Current context (sent and received message). 908 Context context_; 909 910 /// @brief Current transaction id (altered on each send). 911 uint32_t curr_transid_; 912 913 /// @brief Currently used destination address. 914 asiolink::IOAddress dest_addr_; 915 916 /// @brief Currently used DUID. 917 DuidPtr duid_; 918 919 /// @brief Currently used link local address. 920 asiolink::IOAddress link_local_; 921 922 /// @brief Currently used interface (name). 923 std::string iface_name_; 924 925 /// @brief Currently used interface (index). 926 uint32_t iface_index_; 927 928 /// @brief Pointer to the server that the client is communicating with. 929 boost::shared_ptr<isc::dhcp::test::NakedDhcpv6Srv> srv_; 930 931 bool use_relay_; ///< Enable relaying messages to the server. 932 933 bool use_oro_; ///< Conth 934 bool use_docsis_oro_; 935 bool use_client_id_; 936 bool use_rapid_commit_; 937 938 /// @brief List holding information to be sent in client's IAs. 939 std::list<ClientIA> client_ias_; 940 941 /// @brief List of options to be requested 942 /// 943 /// Content of this vector will be sent as ORO if use_oro_ is set 944 /// to true. See @ref sendORO for details. 945 std::vector<uint16_t> oro_; 946 947 /// @brief List of DOCSIS vendor options to be requested 948 /// 949 /// Content of this vector will be sent as DOCSIS vendor ORO if 950 /// use_docsis_oro_ is set to true. See @ref sendDocsisORO for details. 951 std::vector<uint16_t> docsis_oro_; 952 953 /// @brief forced (Overridden) value of the server-id option (may be NULL) 954 OptionPtr forced_server_id_; 955 956 /// @brief Extra options the client will send. 957 OptionCollection extra_options_; 958 959 /// @brief FQDN requested by the client. 960 Option6ClientFqdnPtr fqdn_; 961 962 /// @brief Interface id. 963 OptionPtr interface_id_; 964 965 /// @brief Extra classes to add to the query. 966 ClientClasses classes_; 967 }; 968 969 } // end of namespace isc::dhcp::test 970 } // end of namespace isc::dhcp 971 } // end of namespace isc 972 973 #endif // DHCP6_CLIENT 974