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