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