summaryrefslogtreecommitdiffstats
path: root/src/bin/dhcp6/tests/dhcp6_client.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/dhcp6/tests/dhcp6_client.h')
-rw-r--r--src/bin/dhcp6/tests/dhcp6_client.h973
1 files changed, 973 insertions, 0 deletions
diff --git a/src/bin/dhcp6/tests/dhcp6_client.h b/src/bin/dhcp6/tests/dhcp6_client.h
new file mode 100644
index 0000000..e236a3d
--- /dev/null
+++ b/src/bin/dhcp6/tests/dhcp6_client.h
@@ -0,0 +1,973 @@
+// Copyright (C) 2014-2020 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef DHCP6_CLIENT_H
+#define DHCP6_CLIENT_H
+
+#include <asiolink/io_address.h>
+#include <dhcp/duid.h>
+#include <dhcp/option.h>
+#include <dhcp/option6_client_fqdn.h>
+#include <dhcpsrv/lease.h>
+#include <dhcp6/tests/dhcp6_test_utils.h>
+#include <util/staged_value.h>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <list>
+#include <set>
+#include <vector>
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+/// @brief DHCPv6 client used for unit testing.
+///
+/// This class implements a DHCPv6 "client" which interoperates with the
+/// @c NakedDhcpv6Srv class. It calls @c NakedDhcpv6Srv::fakeReceive to
+/// deliver client messages to the server for processing. The server places
+/// the response in the @c NakedDhcpv6Srv::fake_sent_ container. The client
+/// pops messages from this container which simulates reception of the
+/// response from the server.
+///
+/// The client maintains the leases it acquired from the server. If it has
+/// acquired the lease as a result of SARR exchange, it will use this lease
+/// when the Rebind process is triggered by the unit test.
+///
+/// The client exposes a set of functions which simulate different exchange
+/// types between the client and the server. It also provides the access to
+/// the objects encapsulating responses from the server so as it is possible
+/// to verify from the unit test that the server's response is correct.
+///
+/// @todo This class has been implemented to simplify the structure of the
+/// unit test and to make unit tests code self-explanatory. Currently,
+/// this class is mostly used by the unit tests which test Rebind processing
+/// logic. At some point we may want to use this class to test some other
+/// message types, e.g. Renew, in which case it may need to be extended.
+/// Also, once we implement the support for multiple IAAddr and IAPrefix
+/// options within single IA, the logic which maintains leases will have
+/// to be extended to support it.
+class Dhcp6Client : public boost::noncopyable {
+public:
+
+ /// @brief Holds an information about single lease.
+ struct LeaseInfo {
+ /// @brief A structure describing the lease.
+ Lease6 lease_;
+
+ /// @brief Holds the last status code that server has sent for
+ /// the particular lease.
+ uint16_t status_code_;
+
+ /// @brief Default constructor for the structure.
+ LeaseInfo() :
+ lease_(), status_code_(0) { }
+
+ /// @brief Constructor which sets the lease type.
+ ///
+ /// @param lease_type One of the D6O_IA_NA or D6O_IA_PD.
+ LeaseInfo(const uint16_t lease_type) :
+ lease_(), status_code_(0) {
+ lease_.type_ = lease_type == D6O_IA_NA ? Lease::TYPE_NA :
+ Lease::TYPE_PD;
+ }
+ };
+
+ /// @brief Holds the current client configuration obtained from the
+ /// server over DHCP.
+ ///
+ /// Currently it simply contains the collection of leases acquired
+ /// and a list of options. Note: this is a simple copy of all
+ /// non-IA options and often includes "protocol" options, like
+ /// server-id and client-id.
+ struct Configuration {
+ /// @brief List of received leases
+ std::vector<Lease6> leases_;
+
+ /// @brief A map of IAID, status code tuples.
+ std::map<uint32_t, uint16_t> status_codes_;
+
+ /// @brief List of received options
+ OptionCollection options_;
+
+ /// @brief Status code received in the global option scope.
+ uint16_t status_code_;
+
+ /// @brief Indicates if the status code has been received in the
+ /// last transaction.
+ bool received_status_code_;
+
+ /// @brief Constructor.
+ Configuration() {
+ clear();
+ }
+
+ /// @brief Clears configuration.
+ void clear() {
+ leases_.clear();
+ status_codes_.clear();
+ resetGlobalStatusCode();
+ options_.clear();
+ }
+
+ /// @brief Clears global status code.
+ ///
+ /// This function should be called before the new message is received.
+ void resetGlobalStatusCode() {
+ status_code_ = 0;
+ received_status_code_ = false;
+ }
+
+ /// @brief Finds an option with the specific code in the received
+ /// configuration.
+ ///
+ /// @param code Option code.
+ ///
+ /// @return Pointer to the option if the option exists, or NULL if
+ /// the option doesn't exist.
+ OptionPtr findOption(const uint16_t code) const {
+ std::multimap<unsigned int, OptionPtr>::const_iterator it = options_.find(code);
+ if (it != options_.end()) {
+ return (it->second);
+ }
+ return (OptionPtr());
+ }
+ };
+
+ /// @brief Holds the DHCPv6 messages taking part in transaction between
+ /// the client and the server.
+ struct Context {
+ /// @brief Holds the last sent message from the client to the server.
+ Pkt6Ptr query_;
+ /// @brief Holds the last sent message by the server to the client.
+ Pkt6Ptr response_;
+ };
+
+ /// @brief Structure holding information to be placed in client's IA.
+ struct ClientIA {
+ Lease::Type type_; ///< IA type
+ uint32_t iaid_; ///< IAID
+ asiolink::IOAddress prefix_; ///< prefix or address
+ uint8_t prefix_len_; ///< prefix length
+
+ /// @brief Constructor.
+ ///
+ /// @param type IA type.
+ /// @param iaid IAID.
+ /// @param prefix Address or prefix.
+ /// @param prefix_len Prefix length.
+ ClientIA(const Lease::Type& type, const uint32_t iaid,
+ const asiolink::IOAddress& prefix,
+ const uint8_t prefix_len)
+ : type_(type), iaid_(iaid), prefix_(prefix),
+ prefix_len_(prefix_len) {
+ }
+ };
+
+ /// @brief Creates a new client.
+ ///
+ /// This constructor initializes the class members to default values:
+ /// - relay link-addr = 3000:1::1
+ /// - first transaction id = 0
+ /// - dest-addr = All_DHCP_Relay_Agents_and_Servers
+ /// - duid (LLT) = <random 4 bytes>00010203040506
+ /// - link-local-addr = fe80::3a60:77ff:fed5:cdef
+ /// - IA_NA not requested
+ /// - IA_PD not requested
+ /// - not relayed
+ Dhcp6Client();
+
+ /// @brief Creates a new client that communicates with a specified server.
+ ///
+ /// This constructor allows passing a pointer to the server object which
+ /// should be used in a test. The server may be preconfigured before passed
+ /// to the constructor. The default configuration used by the client is:
+ /// - relay link-addr = 3000:1::1
+ /// - first transaction id = 0
+ /// - dest-addr = All_DHCP_Relay_Agents_and_Servers
+ /// - duid (LLT) = <random 4 bytes>00010203040506
+ /// - link-local-addr = fe80::3a60:77ff:fed5:cdef
+ /// - IA_NA not requested
+ /// - IA_PD not requested
+ /// - not relayed
+ ///
+ /// @param srv Object representing server under test.
+ Dhcp6Client(boost::shared_ptr<isc::dhcp::test::NakedDhcpv6Srv>& srv);
+
+ /// @brief Create lease for the client.
+ ///
+ /// This function creates new lease on the client side without contacting
+ /// the server. This may be useful for the negative tests in which the
+ /// client is supposed to send invalid addresses/prefixes to the server
+ /// and expect certain responses.
+ ///
+ /// @param lease A lease to be applied for the client.
+ void createLease(const Lease6& lease);
+
+ /// @brief Performs a 4-way exchange between the client and the server.
+ ///
+ /// If the 4-way exchange is successful, the client should acquire leases
+ /// according to the server's current configuration and the type of leases
+ /// that have been requested (IA_NA, IA_PD).
+ ///
+ /// The leases acquired are accessible through the @c config_ member.
+ ///
+ /// @throw This function doesn't throw exceptions on its own, but it calls
+ /// functions that are not exception safe, so it may throw exceptions if
+ /// error occurs.
+ ///
+ /// @todo Perform sanity checks on returned messages.
+ void doSARR();
+
+ /// @brief Send Solicit and receive Advertise.
+ ///
+ /// This function simulates the first transaction of the 4-way exchange,
+ /// i.e. sends a Solicit to the server and receives Advertise. It doesn't
+ /// set the lease configuration in the @c config_.
+ ///
+ /// @param always_apply_config Apply received configuration even if the
+ /// Advertise message is received. Default value is false.
+ ///
+ /// @throw This function doesn't throw exceptions on its own, but it calls
+ /// functions that are not exception safe, so it may throw exceptions if
+ /// error occurs.
+ ///
+ /// @todo Perform sanity checks on returned messages.
+ void doSolicit(const bool always_apply_config = false);
+
+ /// @brief Sends a Renew to the server and receives the Reply.
+ ///
+ /// This function simulates sending the Renew message to the server and
+ /// receiving server's response (if any). The client uses existing leases
+ /// (either address or prefixes) and places them in the Renew message.
+ /// If the server responds to the Renew (and extends the lease lifetimes)
+ /// the current lease configuration is updated.
+ ///
+ /// @throw This function doesn't throw exceptions on its own, but it calls
+ /// functions that are not exception safe, so it may throw exceptions if
+ /// error occurs.
+ ///
+ /// @todo Perform sanity checks on returned messages.
+ void doRenew();
+
+ /// @brief Sends a Rebind to the server and receives the Reply.
+ ///
+ /// This function simulates sending the Rebind message to the server and
+ /// receiving server's response (if any). The client uses existing leases
+ /// (either address or prefixes) and places them in the Rebind message.
+ /// If the server responds to the Rebind (and extends the lease lifetimes)
+ /// the current lease configuration is updated.
+ ///
+ /// @throw This function doesn't throw exceptions on its own, but it calls
+ /// functions that are not exception safe, so it may throw exceptions if
+ /// error occurs.
+ ///
+ /// @todo Perform sanity checks on returned messages.
+ void doRebind();
+
+ /// @brief Sends Request to the server and receives Reply.
+ ///
+ /// This function simulates sending the Request message to the server and
+ /// receiving server's response (if any). The client copies IA options
+ /// from the current context (server's Advertise) to request acquisition
+ /// of offered IAs. If the server responds to the Request (leases are
+ /// acquired) the client's lease configuration is updated.
+ ///
+ /// @throw This function doesn't throw exceptions on its own, but it calls
+ /// functions that are not exception safe, so it may throw exceptions if
+ /// error occurs.
+ ///
+ /// @todo Perform sanity checks on returned messages.
+ void doRequest();
+
+ /// @brief Sends Confirm to the server and receives Reply.
+ ///
+ /// This function simulates sending the Confirm message to the server and
+ /// receiving server's response (if any).
+ void doConfirm();
+
+ /// @brief Sends Decline to the server and receives Reply.
+ ///
+ /// This function simulates sending the Decline message to the server and
+ /// receiving the server's response.
+ /// @param include_address should the address be included?
+ void doDecline(const bool include_address = true);
+
+ /// @brief Performs stateless (inf-request / reply) exchange.
+ ///
+ /// This function generates Information-request message, sends it
+ /// to the server and then receives the reply. Contents of the Inf-Request
+ /// are controlled by client_ias_, use_client_id_ and use_oro_
+ /// fields. This method does not process the response in any specific
+ /// way, just stores it.
+ void doInfRequest();
+
+ /// @brief Sends Release to the server.
+ ///
+ /// This function simulates sending the Release message to the server
+ /// and receiving server's response.
+ void doRelease();
+
+ /// @brief Removes the stateful configuration obtained from the server.
+ ///
+ /// It removes all leases held by the client.
+ void clearConfig() {
+ config_.clear();
+ }
+
+ /// @brief Simulates aging of leases by the specified number of seconds.
+ ///
+ /// This function moves back the time of acquired leases by the specified
+ /// number of seconds. It is useful for checking whether the particular
+ /// lease has been later updated (e.g. as a result of Rebind) as it is
+ /// expected that the fresh lease has cltt set to "now" (not to the time
+ /// in the past).
+ ///
+ /// @param secs Number of seconds by which the time should be moved.
+ /// @param update_server Indicates if the leases should be updated on the
+ /// server.
+ void fastFwdTime(const uint32_t secs, const bool update_server = false);
+
+ /// @brief Returns DUID option used by the client.
+ OptionPtr getClientId() const;
+
+ /// @brief Returns current context.
+ const Context& getContext() const {
+ return (context_);
+ }
+
+ /// @brief Returns the collection of IAIDs held by the client.
+ std::set<uint32_t> getIAIDs() const;
+
+ /// @brief Returns lease at specified index.
+ ///
+ /// @warning This method doesn't check if the specified index is out of
+ /// range. The caller is responsible for using a correct offset by
+ /// invoking the @c getLeaseNum function.
+ ///
+ /// @param at Index of the lease held by the client.
+ /// @return A lease at the specified index.
+ Lease6 getLease(const size_t at) const {
+ return (config_.leases_[at]);
+ }
+
+ /// @brief Returns collection of leases for specified IAID.
+ ///
+ /// @param iaid IAID for which the leases should be returned.
+ ///
+ /// @return Vector containing leases for the IAID.
+ std::vector<Lease6> getLeasesByIAID(const uint32_t iaid) const;
+
+ /// @brief Returns collection of leases by type.
+ ///
+ /// @param type Lease type: D6O_IA_NA or D6O_IA_PD.
+ ///
+ /// @return Vector containing leases of the specified type.
+ std::vector<Lease6> getLeasesByType(const Lease::Type& lease_type) const;
+
+ /// @brief Returns leases with non-zero lifetimes.
+ std::vector<Lease6> getLeasesWithNonZeroLifetime() const;
+
+ /// @brief Returns leases with zero lifetimes.
+ std::vector<Lease6> getLeasesWithZeroLifetime() const;
+
+ /// @brief Returns leases by lease address/prefix.
+ ///
+ /// @param address Leased address.
+ ///
+ /// @return Vector containing leases for the specified address.
+ std::vector<Lease6>
+ getLeasesByAddress(const asiolink::IOAddress& address) const;
+
+ /// @brief Returns leases belonging to specified address range.
+ ///
+ /// @param first Lower bound of the address range.
+ /// @param second Upper bound of the address range.
+ ///
+ /// @return Vector containing leases belonging to specified address range.
+ std::vector<Lease6>
+ getLeasesByAddressRange(const asiolink::IOAddress& first,
+ const asiolink::IOAddress& second) const;
+
+ /// @brief Returns leases belonging to prefix pool.
+ ///
+ /// @param prefix Prefix of the pool.
+ /// @param prefix_len Prefix length.
+ /// @param delegated_len Delegated prefix length.
+ ///
+ /// @return Vector containing leases belonging to specified prefix pool.
+ std::vector<Lease6>
+ getLeasesByPrefixPool(const asiolink::IOAddress& prefix,
+ const uint8_t prefix_len,
+ const uint8_t delegated_len) const;
+
+ /// @brief Checks if client has lease for the specified address.
+ ///
+ /// @param address Address for which lease should be found.
+ ///
+ /// @return true if client has lease for the address, false otherwise.
+ bool hasLeaseForAddress(const asiolink::IOAddress& address) const;
+
+ /// @brief Checks if client has lease for the specified address in the
+ /// IA_NA identified by IAID.
+ ///
+ /// @param address Address for which lease should be found.
+ /// @param iaid IAID of the IA_NA in which the lease is expected.
+ bool hasLeaseForAddress(const asiolink::IOAddress& address,
+ const IAID& iaid) const;
+
+ /// @brief Checks if client has a lease for an address within range.
+ ///
+ /// @param first Lower bound of the address range.
+ /// @param last Upper bound of the address range.
+ ///
+ /// @return true if client has lease for the address within the range,
+ /// false otherwise.
+ bool hasLeaseForAddressRange(const asiolink::IOAddress& first,
+ const asiolink::IOAddress& last) const;
+
+ /// @brief Checks if client has a lease with zero lifetimes for the
+ /// specified address.
+ ///
+ /// @param address Address for which lease should be found.
+ ///
+ /// @return true if client has a lease, false otherwise.
+ bool hasLeaseWithZeroLifetimeForAddress(const asiolink::IOAddress& address) const;
+
+ /// @brief Checks if client has a lease for a prefix.
+ ///
+ /// @param prefix Prefix.
+ /// @param prefix_len Prefix length.
+ ///
+ /// @return true if client has a lease for the specified prefix, false
+ /// otherwise.
+ bool hasLeaseForPrefix(const asiolink::IOAddress& prefix,
+ const uint8_t prefix_len) const;
+
+ /// @brief Checks if client as a lease for prefix in the IA_PD identified
+ /// by specified IAID.
+ ///
+ /// @param prefix Prefix.
+ /// @param prefix_len Prefix length.
+ /// @param iaid IAID of the IA_PD in which the lease is expected.
+ bool hasLeaseForPrefix(const asiolink::IOAddress& prefix,
+ const uint8_t prefix_len,
+ const IAID& iaid) const;
+
+ /// @brief Checks if client has a lease belonging to a prefix pool.
+ ///
+ /// @param prefix Pool prefix.
+ /// @param prefix_len Prefix length.
+ /// @param delegated_len Delegated prefix length.
+ ///
+ /// @return true if client has a lease belonging to specified pool,
+ /// false otherwise.
+ bool hasLeaseForPrefixPool(const asiolink::IOAddress& prefix,
+ const uint8_t prefix_len,
+ const uint8_t delegated_len) const;
+
+ /// @brief Checks if client has a lease with zero lifetimes for a prefix.
+ ///
+ /// @param prefix Prefix.
+ /// @param prefix_len Prefix length.
+ ///
+ /// @return true if client has a lease with zero lifetimes for a prefix.
+ bool hasLeaseWithZeroLifetimeForPrefix(const asiolink::IOAddress& prefix,
+ const uint8_t prefix_len) const;
+
+ /// @brief Checks that specified option exists and contains a desired
+ /// address.
+ ///
+ /// The option must cast to the @ref Option6AddrLst type. The function
+ /// expects that this option contains at least one address and checks
+ /// first address for equality with @ref expected_address.
+ ///
+ /// @param option_type Option type.
+ /// @param expected_address Desired address.
+ /// @param config Configuration obtained from the server.
+ bool hasOptionWithAddress(const uint16_t option_type,
+ const std::string& expected_address) const;
+
+ /// @brief Returns the value of the global status code for the last
+ /// transaction.
+ uint16_t getStatusCode() const {
+ return (config_.status_code_);
+ }
+
+ /// @brief Returns status code set by the server for the IAID.
+ ///
+ /// @param iaid for which the status is desired
+ /// @return A status code for the given iaid
+ uint16_t getStatusCode(const uint32_t iaid) const;
+
+ /// @brief Returns T1 and T2 timers associated with a given iaid
+ ///
+ /// Changed to get the T1 an T2 times from acquired leases to
+ /// IA options.
+ ///
+ /// @param iaid iaid of the target IA
+ /// @param[out] t1 set to the value of the IA's T1
+ /// @param[out] t2 set to the value of the IA's T2
+ /// @return true if there is an IA option for the given iaid
+ bool getTeeTimes(const uint32_t iaid, uint32_t& t1, uint32_t& t2) const;
+
+ /// @brief Returns number of acquired leases.
+ size_t getLeaseNum() const {
+ return (config_.leases_.size());
+ }
+
+ /// @brief Returns the server that the client is communicating with.
+ boost::shared_ptr<isc::dhcp::test::NakedDhcpv6Srv>& getServer() {
+ return (srv_);
+ }
+
+ /// @brief Sets the client's DUID from a string value
+ ///
+ /// Replaces the client's DUID with one constructed from the given
+ /// string. The string is expected to contain hexadecimal digits with or
+ /// without ":" separators.
+ ///
+ /// @param str The string of digits from which to create the DUID
+ ///
+ /// The DUID modification affects the value returned by the
+ /// @c Dhcp6Client::getClientId
+ void setDUID(const std::string& duid_str);
+
+ /// @brief Modifies the client's DUID (adds one to it).
+ ///
+ /// The DUID should be modified to test negative scenarios when the client
+ /// acquires a lease and tries to renew it with a different DUID. The server
+ /// should detect the DUID mismatch and react accordingly.
+ ///
+ /// The DUID modification affects the value returned by the
+ /// @c Dhcp6Client::getClientId
+ void modifyDUID();
+
+ /// @brief Checks if the global status code was received in the response
+ /// from the server.
+ ///
+ /// @return true if the global status code option was received.
+ bool receivedStatusCode() const {
+ return (config_.received_status_code_);
+ }
+
+ /// @brief Sets destination address for the messages being sent by the
+ /// client.
+ ///
+ /// By default, the client uses All_DHCP_Relay_Agents_and_Servers
+ /// multicast address to communicate with the server. In certain cases
+ /// it may be desired that different address is used (e.g. unicast in Renew).
+ /// This function sets the new address for all future exchanges with the
+ /// server.
+ ///
+ /// @param dest_addr New destination address.
+ void setDestAddress(const asiolink::IOAddress& dest_addr) {
+ dest_addr_ = dest_addr;
+ }
+
+ /// @brief Sets the interface to be used by the client.
+ ///
+ /// @param iface_name Interface name.
+ void setInterface(const std::string& iface_name) {
+ iface_name_ = iface_name;
+ }
+
+ /// @brief Sets the interface to be used by the client.
+ ///
+ /// @param iface_index Interface index.
+ void setIfaceIndex(uint32_t iface_index) {
+ iface_index_ = iface_index;
+ }
+
+ /// @brief Sets link local address used by the client.
+ ///
+ /// @param link_local New link local address.
+ void setLinkLocal(const asiolink::IOAddress& link_local) {
+ link_local_ = link_local;
+ }
+
+ /// @brief Specifies address to be included in client's message.
+ ///
+ /// This method specifies IPv6 address to be included within IA_NA
+ /// option sent by the client. In order to specify multiple addresses
+ /// to be included in a particular IA_NA, this method must be called
+ /// multiple times to specify each address separately. In such case,
+ /// the value of the IAID should remain the same across all calls to
+ /// this method.
+ ///
+ /// This method is typically called to specify IA_NA options to be
+ /// sent to the server during 4-way handshakes and during lease
+ /// renewal to request allocation of new leases (as per RFC 8415).
+ ///
+ /// @param iaid IAID.
+ /// @param address IPv6 address to be included in the IA_NA. It defaults
+ /// to IPv6 zero address, which indicates that no address should be
+ /// included in the IA_NA (empty IA_NA will be sent).
+ void requestAddress(const uint32_t iaid = 1234,
+ const asiolink::IOAddress& address =
+ asiolink::IOAddress::IPV6_ZERO_ADDRESS());
+
+ /// @brief Specifies IPv6 prefix to be included in client's message.
+ ///
+ /// This method specifies IPv6 prefix to be included within IA_PD
+ /// option sent by the client. In order to specify multiple prefixes
+ /// to be included in a particular IA_PD, this method must be called
+ /// multiple times to specify each prefix separately. In such case,
+ /// the value of the IAID should remain the same across all calls to
+ /// this method.
+ ///
+ /// This method is typically called to specify IA_PD options to be
+ /// sent to the server during 4-way handshakes and during lease
+ /// renewal to request allocation of new leases (as per RFC 8415).
+ ///
+ /// @param iaid IAID.
+ /// @param prefix_len Prefix length.
+ /// @param prefix Prefix to be included. This value defaults to the
+ /// IPv6 zero address. If zero address is specified and prefix_len is
+ /// set to 0, the IA Prefix option will not be included in the IA_PD.
+ /// If the prefix_len is non-zero and the prefix is IPv6 zero address
+ /// the prefix length hint will be included in the IA Prefix option.
+ void requestPrefix(const uint32_t iaid = 5678,
+ const uint8_t prefix_len = 0,
+ const asiolink::IOAddress& prefix =
+ asiolink::IOAddress::IPV6_ZERO_ADDRESS());
+
+ /// @brief Removes IAs specified by @ref requestAddress and
+ /// @ref requestPrefix methods.
+ ///
+ /// If this method is called and the client initiates an exchange with
+ /// a server the client will only include IAs for which it has leases.
+ /// If the client has no leases (e.g. a Solicit case), no IAs will be
+ /// included in the client's message.
+ void clearRequestedIAs() {
+ client_ias_.clear();
+ }
+
+ /// @brief Simulate sending messages through a relay.
+ ///
+ /// @param use Parameter which 'true' value indicates that client should
+ /// simulate sending messages via relay.
+ /// @param link_addr Relay link-addr.
+ void useRelay(const bool use = true,
+ const asiolink::IOAddress& link_addr = asiolink::IOAddress("3000:1::1")) {
+ use_relay_ = use;
+ relay_link_addr_ = link_addr;
+ }
+
+ /// @brief Sets interface id value to be inserted into relay agent option.
+ ///
+ /// @param interface_id Value of the interface id as string.
+ void useInterfaceId(const std::string& interface_id);
+
+ /// @brief Controls whether the client should send a client-id or not
+ /// @param send should the client-id be sent?
+ void useClientId(const bool send) {
+ use_client_id_ = send;
+ }
+
+ /// @brief Specifies if the Rapid Commit option should be included in
+ /// the Solicit message.
+ ///
+ /// @param rapid_commit Boolean parameter controlling if the Rapid Commit
+ /// option must be included in the Solicit (if true), or not (if false).
+ void useRapidCommit(const bool rapid_commit) {
+ use_rapid_commit_ = rapid_commit;
+ }
+
+ /// @brief Specifies server-id to be used in send messages
+ ///
+ /// Overrides the server-id to be sent when server-id is expected to be
+ /// sent. May be NULL, which means use proper server-id sent in Advertise
+ /// (which is a normal client behavior).
+ ///
+ /// @param server_id server-id to be sent
+ void useServerId(const OptionPtr& server_id) {
+ forced_server_id_ = server_id;
+ }
+
+ /// @brief Creates an instance of the Client FQDN option to be included
+ /// in the client's message.
+ ///
+ /// @param flags Flags.
+ /// @param fqdn_name Name in the textual format.
+ /// @param fqdn_type Type of the name (fully qualified or partial).
+ void useFQDN(const uint8_t flags, const std::string& fqdn_name,
+ Option6ClientFqdn::DomainNameType fqdn_type);
+
+ /// @brief Lease configuration obtained by the client.
+ Configuration config_;
+
+ /// @brief Link address of the relay to be used for relayed messages.
+ asiolink::IOAddress relay_link_addr_;
+
+ /// @brief RelayInfo (information about relays)
+ ///
+ /// Dhcp6Client will typically construct this info itself, but if
+ /// it is provided here by the test, this data will be used as is.
+ std::vector<Pkt6::RelayInfo> relay_info_;
+
+ /// @brief Controls whether the client will send ORO
+ ///
+ /// The actual content of the ORO is specified in oro_.
+ /// It is useful to split the actual content and the ORO sending
+ /// decision, so we could test cases of sending empty ORO.
+ /// @param send controls whether ORO will be sent or not.
+ void useORO(bool send) {
+ use_oro_ = send;
+ }
+
+ /// @brief Instructs client to request specified option in ORO
+ ///
+ /// @param option_code client will request this option code
+ void requestOption(uint16_t option_code) {
+ use_oro_ = true;
+ oro_.push_back(option_code);
+ }
+
+ /// @brief Controls whether the client will send DOCSIS vendor ORO
+ ///
+ /// The actual content of the ORO is specified in docsis_oro_.
+ /// It is useful to split the actual content and the ORO sending
+ /// decision, so we could test cases of sending empty ORO.
+ /// @param send controls whether ORO will be sent or not.
+ void useDocsisORO(bool send) {
+ use_docsis_oro_ = send;
+ }
+
+ /// @brief Instructs client to request specified option in DOCSIS
+ /// vendor ORO
+ ///
+ /// @param option_code client will request this option code
+ void requestDocsisOption(uint16_t option_code) {
+ use_docsis_oro_ = true;
+ docsis_oro_.push_back(option_code);
+ }
+
+ /// @brief returns client-id
+ /// @return client-id
+ DuidPtr getDuid() const {
+ return (duid_);
+ }
+
+ /// @brief Generates IA_NA based on lease information
+ ///
+ /// @param query generated IA_NA options will be added here
+ /// @param include_address should the address be included?
+ void generateIAFromLeases(const Pkt6Ptr& query,
+ const bool include_address = true);
+
+ /// @brief Adds extra option (an option the client will always send)
+ ///
+ /// @param opt additional option to be sent
+ void addExtraOption(const OptionPtr& opt);
+
+ /// @brief Configures the client to not send any extra options.
+ void clearExtraOptions();
+
+ /// @brief Add a client class.
+ ///
+ /// @param client_class name of the class to be added.
+ void addClass(const ClientClass& client_class);
+
+ /// @brief Configures the client to not add client classes.
+ void clearClasses();
+
+ /// @brief Debugging method the prints currently held configuration
+ ///
+ /// @todo: This is mostly useful when debugging tests. This method
+ /// is incomplete. Please extend it when needed.
+ void printConfiguration() const;
+
+ /// @brief Receives a response from the server.
+ ///
+ /// This method is useful to receive response from the server after
+ /// parking a packet. In this case, the packet is not received as a
+ /// result of initial exchange, e.g. @c doRequest. The test can call
+ /// this method to complete the transaction when it expects that the
+ /// packet has been unparked.
+ void receiveResponse();
+
+private:
+
+ /// @brief Applies the new leases for the client.
+ ///
+ /// This method is called when the client obtains a new configuration
+ /// from the server in the Reply message. This function adds new leases
+ /// or replaces existing ones, on the client's side. Client uses these
+ /// leases in any later communication with the server when doing Renew
+ /// or Rebind.
+ ///
+ /// @param reply Server response.
+ /// @param state specifies lease state (see Lease::STATE_* for details).
+ ///
+ /// The default for state is 0. We could have included dhcpsrv/lease.h
+ /// and used Lease::STATE_DEFAULT, but that would complicate the header
+ /// inclusion dependencies. It's easier to simply use 0 as the default.
+ ///
+ /// @todo Currently this function supports one IAAddr or IAPrefix option
+ /// within IA. We will need to extend it to support multiple options
+ /// within a single IA once server supports that.
+ void applyRcvdConfiguration(const Pkt6Ptr& reply, uint32_t state = 0);
+
+ /// @brief Applies configuration for the single lease.
+ ///
+ /// This method is called by the @c Dhcp6Client::applyRcvdConfiguration for
+ /// each individual lease.
+ ///
+ /// @param lease_info Structure holding new lease information.
+ void applyLease(const Lease6& lease);
+
+ /// @brief Includes Client FQDN in the client's message.
+ ///
+ /// This method checks if @c fqdn_ is specified and includes it in
+ /// the client's message.
+ void appendFQDN();
+
+ /// @brief Includes IAs to be requested.
+ ///
+ /// This method includes IAs explicitly requested using client_ias_
+ ///
+ /// @param query Pointer to the client's message to which IAs should be
+ /// added.
+ void appendRequestedIAs(const Pkt6Ptr& query) const;
+
+ /// @brief Copy IA options from one message to another.
+ ///
+ /// This method copies IA_NA and IA_PD options from one message to another.
+ /// It is useful when the client needs to construct the Request message
+ /// using addresses and prefixes returned by the client in Advertise.
+ ///
+ /// @param source Message from which IA options will be copied.
+ /// @param dest Message to which IA options will be copied.
+ ///
+ /// @todo Add support for IA_TA.
+ void copyIAs(const Pkt6Ptr& source, const Pkt6Ptr& dest);
+
+ /// @brief Creates IA options from existing configuration.
+ ///
+ /// This method iterates over existing leases that client acquired and
+ /// places corresponding IA_NA or IA_PD options into a specified message.
+ /// This is useful to construct Renew, Rebind or Confirm message from the
+ /// existing configuration that client has obtained using 4-way exchange.
+ ///
+ /// If there are no leases no IA options will be added. If the lease exists
+ /// but any of the lifetime values is set to 0, the IA option will be added
+ /// but the IAAddr (or IAPrefix) option will not be added.
+ ///
+ /// @param dest Message to which the IA options will be added.
+ void copyIAsFromLeases(const Pkt6Ptr& dest) const;
+
+ /// @brief Creates client's side DHCP message.
+ ///
+ /// @param msg_type Type of the message to be created.
+ /// @return An instance of the message created.
+ Pkt6Ptr createMsg(const uint8_t msg_type);
+
+ /// @brief Generates DUID for the client.
+ ///
+ /// @param duid_type Type of the DUID. Currently, only LLT is accepted.
+ /// @return Object encapsulating a DUID.
+ DuidPtr generateDUID(DUID::DUIDType duid_type) const;
+
+ /// @brief Returns client's leases which match the specified condition.
+ ///
+ /// @param property A value of the lease property used to search the lease.
+ /// @param equals A flag which indicates if the operator should search
+ /// for the leases which property is equal to the value of @c property
+ /// parameter (if true), or unequal (if false).
+ /// @param [out] leases A vector in which the operator will store leases
+ /// found.
+ ///
+ /// @tparam BaseType Base type to which the property belongs: @c Lease or
+ /// @c Lease6.
+ /// @tparam PropertyType A type of the property, e.g. @c uint32_t for IAID.
+ /// @tparam MemberPointer A pointer to the member, e.g. @c &Lease6::iaid_.
+ template<typename BaseType, typename PropertyType,
+ PropertyType BaseType::*MemberPointer>
+ void getLeasesByProperty(const PropertyType& property, const bool equals,
+ std::vector<Lease6>& leases) const;
+
+ /// @brief Simulates reception of the message from the server.
+ ///
+ /// @return Received message.
+ Pkt6Ptr receiveOneMsg();
+
+ /// @brief Simulates sending a message to the server.
+ ///
+ /// This function instantly triggers processing of the message by the
+ /// server. The server's response can be gathered by invoking the
+ /// @c receiveOneMsg function.
+ ///
+ /// @param msg Message to be sent.
+ void sendMsg(const Pkt6Ptr& msg);
+
+ /// @brief Current context (sent and received message).
+ Context context_;
+
+ /// @brief Current transaction id (altered on each send).
+ uint32_t curr_transid_;
+
+ /// @brief Currently used destination address.
+ asiolink::IOAddress dest_addr_;
+
+ /// @brief Currently used DUID.
+ DuidPtr duid_;
+
+ /// @brief Currently used link local address.
+ asiolink::IOAddress link_local_;
+
+ /// @brief Currently used interface (name).
+ std::string iface_name_;
+
+ /// @brief Currently used interface (index).
+ uint32_t iface_index_;
+
+ /// @brief Pointer to the server that the client is communicating with.
+ boost::shared_ptr<isc::dhcp::test::NakedDhcpv6Srv> srv_;
+
+ bool use_relay_; ///< Enable relaying messages to the server.
+
+ bool use_oro_; ///< Conth
+ bool use_docsis_oro_;
+ bool use_client_id_;
+ bool use_rapid_commit_;
+
+ /// @brief List holding information to be sent in client's IAs.
+ std::list<ClientIA> client_ias_;
+
+ /// @brief List of options to be requested
+ ///
+ /// Content of this vector will be sent as ORO if use_oro_ is set
+ /// to true. See @ref sendORO for details.
+ std::vector<uint16_t> oro_;
+
+ /// @brief List of DOCSIS vendor options to be requested
+ ///
+ /// Content of this vector will be sent as DOCSIS vendor ORO if
+ /// use_docsis_oro_ is set to true. See @ref sendDocsisORO for details.
+ std::vector<uint16_t> docsis_oro_;
+
+ /// @brief forced (Overridden) value of the server-id option (may be NULL)
+ OptionPtr forced_server_id_;
+
+ /// @brief Extra options the client will send.
+ OptionCollection extra_options_;
+
+ /// @brief FQDN requested by the client.
+ Option6ClientFqdnPtr fqdn_;
+
+ /// @brief Interface id.
+ OptionPtr interface_id_;
+
+ /// @brief Extra classes to add to the query.
+ ClientClasses classes_;
+};
+
+} // end of namespace isc::dhcp::test
+} // end of namespace isc::dhcp
+} // end of namespace isc
+
+#endif // DHCP6_CLIENT