dhcp6_srv.h 42.1 KB
Newer Older
1
// Copyright (C) 2011-2018 Internet Systems Consortium, Inc. ("ISC")
2
//
3 4 5
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 7 8 9

#ifndef DHCPV6_SRV_H
#define DHCPV6_SRV_H

10
#include <asiolink/io_service.h>
11
#include <dhcp_ddns/ncr_msg.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
12
#include <dhcp/dhcp6.h>
13
#include <dhcp/duid.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
14
#include <dhcp/option.h>
15
#include <dhcp/option6_client_fqdn.h>
16
#include <dhcp/option6_ia.h>
17
#include <dhcp/option_definition.h>
18
#include <dhcp/pkt6.h>
19
#include <dhcpsrv/alloc_engine.h>
20
#include <dhcpsrv/callout_handle_store.h>
21
#include <dhcpsrv/cfg_option.h>
22
#include <dhcpsrv/d2_client_mgr.h>
23
#include <dhcpsrv/network_state.h>
24
#include <dhcpsrv/subnet.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
25
#include <hooks/callout_handle.h>
26
#include <dhcpsrv/daemon.h>
27

28
#include <functional>
29
#include <iostream>
30
#include <queue>
31

32 33 34 35
// Undefine the macro OPTIONAL which is defined in some operating
// systems but conflicts with a member of the RequirementLevel enum in
// the server class.

36 37 38 39
#ifdef OPTIONAL
#undef OPTIONAL
#endif

40
namespace isc {
41
namespace dhcp {
42

43 44 45 46 47 48 49 50
/// @brief This exception is thrown when DHCP server hits the error which should
/// result in discarding the message being processed.
class DHCPv6DiscardMessageError : public Exception {
public:
    DHCPv6DiscardMessageError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

51 52
/// @brief DHCPv6 server service.
///
Stephen Morris's avatar
Stephen Morris committed
53
/// This class represents DHCPv6 server. It contains all
54 55 56 57 58
/// top-level methods and routines necessary for server operation.
/// In particular, it instantiates IfaceMgr, loads or generates DUID
/// that is going to be used as server-identifier, receives incoming
/// packets, processes them, manages leases assignment and generates
/// appropriate responses.
59
class Dhcpv6Srv : public Daemon {
60 61 62 63
private:

    /// @brief Pointer to IO service used by the server.
    asiolink::IOServicePtr io_service_;
64 65

public:
66 67 68 69 70 71
    /// @brief defines if certain option may, must or must not appear
    typedef enum {
        FORBIDDEN,
        MANDATORY,
        OPTIONAL
    } RequirementLevel;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
72 73 74 75

    /// @brief Minimum length of a MAC address to be used in DUID generation.
    static const size_t MIN_MAC_LEN = 6;

76 77 78 79 80 81
    /// @brief Default constructor.
    ///
    /// Instantiates necessary services, required to run DHCPv6 server.
    /// In particular, creates IfaceMgr that will be responsible for
    /// network interaction. Will instantiate lease manager, and load
    /// old or create new DUID.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
82 83
    ///
    /// @param port port on will all sockets will listen
84
    Dhcpv6Srv(uint16_t port = DHCP6_SERVER_PORT);
85 86

    /// @brief Destructor. Used during DHCPv6 service shutdown.
87
    virtual ~Dhcpv6Srv();
88

89 90 91 92 93
    /// @brief Returns pointer to the IO service used by the server.
    asiolink::IOServicePtr& getIOService() {
        return (io_service_);
    }

94 95 96 97 98
    /// @brief Returns pointer to the network state used by the server.
    NetworkStatePtr& getNetworkState() {
        return (network_state_);
    }

99
    /// @brief returns Kea version on stdout and exit.
100
    /// redeclaration/redefinition. @ref Daemon::getVersion()
101
    static std::string getVersion(bool extended);
102

Francis Dupont's avatar
Francis Dupont committed
103
    /// @brief Returns server-identifier option.
104 105
    ///
    /// @return server-id option
106
    OptionPtr getServerID() { return serverid_; }
107 108 109

    /// @brief Main server processing loop.
    ///
Francis Dupont's avatar
Francis Dupont committed
110
    /// Main server processing loop. Call the processing step routine
Francis Dupont's avatar
Francis Dupont committed
111
    /// until shut down.
112
    ///
Francis Dupont's avatar
Francis Dupont committed
113
    /// @return true, if being shut down gracefully, never fail.
114 115
    bool run();

Francis Dupont's avatar
Francis Dupont committed
116
    /// @brief Main server processing step.
Francis Dupont's avatar
Francis Dupont committed
117
    ///
Francis Dupont's avatar
Francis Dupont committed
118
    /// Main server processing step. Receives one incoming packet, calls
119 120
    /// the processing packet routing and (if necessary) transmits
    /// a response.
Francis Dupont's avatar
Francis Dupont committed
121 122
    void run_one();

123 124 125 126 127 128 129
    /// @brief Process a single incoming DHCPv6 packet.
    ///
    /// It verifies correctness of the passed packet, call per-type processXXX
    /// methods, generates appropriate answer.
    ///
    /// @param query A pointer to the packet to be processed.
    /// @param rsp A pointer to the response
130
    void processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp);
131

132 133
    /// @brief Instructs the server to shut down.
    void shutdown();
134

135 136
    /// @brief Get UDP port on which server should listen.
    ///
137 138 139
    /// Typically, server listens on UDP port 547. Other ports are only
    /// used for testing purposes.
    ///
140 141 142 143 144
    /// @return UDP port on which server should listen.
    uint16_t getPort() const {
        return (port_);
    }

145 146
    /// @brief Starts DHCP_DDNS client IO if DDNS updates are enabled.
    ///
147
    /// If updates are enabled, it instructs the D2ClientMgr singleton to
148
    /// enter send mode.  If D2ClientMgr encounters errors it may throw
149
    /// D2ClientError. This method does not catch exceptions.
150 151
    void startD2();

152 153 154 155
    /// @brief Stops DHCP_DDNS client IO if DDNS updates are enabled.
    ///
    /// If updates are enabled, it instructs the D2ClientMgr singleton to
    /// leave send mode.  If D2ClientMgr encounters errors it may throw
156
    /// D2ClientError. This method does not catch exceptions.
157 158
    void stopD2();

159 160
    /// @brief Implements the error handler for DHCP_DDNS IO errors
    ///
161
    /// Invoked when a NameChangeRequest send to kea-dhcp-ddns completes with
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
    /// a failed status.  These are communications errors, not data related
    /// failures.
    ///
    /// This method logs the failure and then suspends all further updates.
    /// Updating can only be restored by reconfiguration or restarting the
    /// server.  There is currently no retry logic so the first IO error that
    /// occurs will suspend updates.
    /// @todo We may wish to make this more robust or sophisticated.
    ///
    /// @param result Result code of the send operation.
    /// @param ncr NameChangeRequest which failed to send.
    virtual void d2ClientErrorHandler(const dhcp_ddns::
                                      NameChangeSender::Result result,
                                      dhcp_ddns::NameChangeRequestPtr& ncr);

177 178 179 180 181
    /// @brief Dumps cached and parked packets
    /// Clears the call_handle store and packet parking lots
    /// of all packets.  Called during reconfigure and shutdown.
    void dumpPackets();

182
protected:
183

184
    /// @brief Compare received server id with our server id
wlodek's avatar
wlodek committed
185
    ///
186 187
    /// Checks if the server id carried in a query from a client matches
    /// server identifier being used by the server.
wlodek's avatar
wlodek committed
188
    ///
189
    /// @param pkt DHCPv6 packet carrying server identifier to be checked.
190 191
    /// @return true if server id carried in the query matches server id
    /// used by the server; false otherwise.
192
    bool testServerID(const Pkt6Ptr& pkt);
193

194 195 196 197 198 199 200 201 202 203 204 205
    /// @brief Check if the message can be sent to unicast.
    ///
    /// This function checks if the received message conforms to the section 15
    /// of RFC3315 which says that: "A server MUST discard any Solicit, Confirm,
    /// Rebind or Information-request messages it receives with a unicast
    /// destination address.
    ///
    /// @param pkt DHCPv6 message to be checked.
    /// @return false if the message has been sent to unicast address but it is
    /// not allowed according to RFC3315, section 15; true otherwise.
    bool testUnicast(const Pkt6Ptr& pkt) const;

206
    /// @brief Verifies if specified packet meets RFC requirements
207 208 209 210 211
    ///
    /// Checks if mandatory option is really there, that forbidden option
    /// is not there, and that client-id or server-id appears only once.
    ///
    /// @param pkt packet to be checked
212 213
    /// @return false if the message should be dropped as a result of the
    /// sanity check.
214 215
    bool sanityCheck(const Pkt6Ptr& pkt);

216 217 218 219 220 221 222 223 224 225 226 227
    /// @brief verifies if specified packet meets RFC requirements
    ///
    /// Checks if mandatory option is really there, that forbidden option
    /// is not there, and that client-id or server-id appears only once.
    ///
    /// @param pkt packet to be checked
    /// @param clientid expectation regarding client-id option
    /// @param serverid expectation regarding server-id option
    /// @throw RFCViolation if any issues are detected
    void sanityCheck(const Pkt6Ptr& pkt, RequirementLevel clientid,
                     RequirementLevel serverid);

228
    /// @brief Processes incoming Solicit and returns response.
229
    ///
230
    /// Processes received Solicit message and verifies that its sender
231
    /// should be served. In particular IA, TA and PD options are populated
232
    /// with to-be assigned addresses, temporary addresses and delegated
233
    /// prefixes, respectively. In the usual 4 message exchange, server is
234 235 236
    /// expected to respond with Advertise message. However, if client
    /// requests rapid-commit and server supports it, Reply will be sent
    /// instead of Advertise and requested leases will be assigned
237 238
    /// immediately.
    ///
239
    /// @param ctx Reference to client context
240
    ///
241
    /// @return Advertise, Reply message or NULL.
242
    Pkt6Ptr processSolicit(AllocEngine::ClientContext6& ctx);
243

244
    /// @brief Processes incoming Request and returns Reply response.
245
    ///
246
    /// Processes incoming Request message and verifies that its sender
247
    /// should be served. In particular IA, TA and PD options are populated
248
    /// with assigned addresses, temporary addresses and delegated
249 250 251
    /// prefixes, respectively. Uses LeaseMgr to allocate or update existing
    /// leases.
    ///
252
    /// @param ctx Reference to client context
253 254
    ///
    /// @return REPLY message or NULL
255
    Pkt6Ptr processRequest(AllocEngine::ClientContext6& ctx);
256

257
    /// @brief Processes incoming Renew message.
258
    ///
259 260
    /// @param ctx Reference to client context
    ///
261
    /// @return Reply message to be sent to the client.
262
    Pkt6Ptr processRenew(AllocEngine::ClientContext6& ctx);
263

264
    /// @brief Processes incoming Rebind message.
265
    ///
266 267 268 269 270 271
    /// @todo There are cases when the Rebind message should be  discarded
    /// by the DHCP server. One of those is when the server doesn't have a
    /// record of the client and it is unable to determine whether the
    /// client is on the appropriate link or not. We don't seem to do it
    /// now.
    ///
272 273
    /// @param ctx Reference to client context
    ///
274
    /// @return Reply message to be sent to the client.
275
    Pkt6Ptr processRebind(AllocEngine::ClientContext6& ctx);
276

277
    /// @brief Processes incoming Confirm message and returns Reply.
278
    ///
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
    /// This function processes Confirm message from the client according
    /// to section 18.2.2. of RFC3315. It discards the Confirm message if
    /// the message sent by the client contains no addresses, i.e. it has
    /// no IA_NA options or all IA_NA options contain no IAAddr options.
    ///
    /// If the Confirm message contains addresses this function will perform
    /// the following checks:
    /// - check if there is appropriate subnet configured for the client
    /// (e.g. subnet from which addresses are assigned for requests
    /// received on the particular interface).
    /// - check if all addresses sent in the Confirm message belong to the
    /// selected subnet.
    ///
    /// If any of the checks above fails, the Reply message with the status
    /// code NotOnLink is returned. Otherwise, the Reply message with the
    /// status code Success is returned.
    ///
296
    /// @param ctx Reference to client context
297
    ///
298
    /// @return Reply message from the server or NULL pointer if Confirm
299
    /// message should be discarded by the server.
300
    Pkt6Ptr processConfirm(AllocEngine::ClientContext6& ctx);
301

302
    /// @brief Process incoming Release message.
303
    ///
304 305
    /// @param ctx Reference to client context
    ///
306
    /// @return Reply message to be sent to the client.
307
    Pkt6Ptr processRelease(AllocEngine::ClientContext6& ctx);
308

Tomek Mrugalski's avatar
Tomek Mrugalski committed
309 310 311 312 313 314 315
    /// @brief Process incoming Decline message.
    ///
    /// This method processes Decline message. It conducts standard sanity
    /// checks, creates empty reply and copies the necessary options from
    /// the client's message. Finally, it calls @ref declineLeases, where
    /// the actual address processing takes place.
    ///
316 317 318
    /// @param ctx Reference to client context
    ///
    /// @return Reply message to be sent to the client.
319
    Pkt6Ptr processDecline(AllocEngine::ClientContext6& ctx);
320

321
    /// @brief Processes incoming Information-request message.
322
    ///
323 324
    /// @param ctx Reference to client context
    ///
325
    /// @return Reply message to be sent to the client.
326
    Pkt6Ptr processInfRequest(AllocEngine::ClientContext6& ctx);
327

Francis Dupont's avatar
Francis Dupont committed
328 329
    /// @brief Processes incoming DHCPv4-query message.
    ///
330 331 332 333 334
    /// It always returns NULL, as there is nothing to be sent back to the
    /// client at this time. The message was sent to DHCPv4 server using
    /// @ref isc::dhcp::Dhcp6to4Ipc::handler()). We will send back a response
    /// to the client once we get back DHCP4-REPLY from the DHCPv4 server.
    ///
Francis Dupont's avatar
Francis Dupont committed
335
    /// @param dhcp4_query message received from client
336
    /// Does not throw
337
    void processDhcp4Query(const Pkt6Ptr& dhcp4_query);
Francis Dupont's avatar
Francis Dupont committed
338

Tomek Mrugalski's avatar
Tomek Mrugalski committed
339
    /// @brief Selects a subnet for a given client's packet.
340
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
341
    /// @param question client's message
342
    /// @param drop if it is true the packet will be dropped
343
    /// @return selected subnet (or NULL if no suitable subnet was found)
344
    isc::dhcp::Subnet6Ptr selectSubnet(const Pkt6Ptr& question, bool& drop);
345

Tomek Mrugalski's avatar
Tomek Mrugalski committed
346
    /// @brief Processes IA_NA option (and assigns addresses if necessary).
347 348
    ///
    /// Generates response to IA_NA. This typically includes selecting (and
349
    /// allocating a lease in case of REQUEST) an address lease and creating
350 351 352 353
    /// IAADDR option. In case of allocation failure, it may contain
    /// status code option with non-zero status, denoting cause of the
    /// allocation failure.
    ///
354
    /// @param query client's message (typically SOLICIT or REQUEST)
355 356 357
    /// @param answer server's response to the client's message. This
    /// message should contain Client FQDN option being sent by the server
    /// to the client (if the client sent this option to the server).
358
    /// @param ctx client context (contains subnet, duid and other parameters)
359
    /// @param ia pointer to client's IA_NA option (client's request)
360
    ///
361
    /// @return IA_NA option (server's response)
362
    OptionPtr assignIA_NA(const isc::dhcp::Pkt6Ptr& query,
363
                          const isc::dhcp::Pkt6Ptr& answer,
364
                          AllocEngine::ClientContext6& ctx,
365
                          Option6IAPtr ia);
366

367 368 369
    /// @brief Processes IA_PD option (and assigns prefixes if necessary).
    ///
    /// Generates response to IA_PD. This typically includes selecting (and
370 371 372
    /// allocating in the case of REQUEST) a prefix lease and creating an
    /// IAPREFIX option. In case of an allocation failure, it may contain a
    /// status code option with non-zero status denoting the cause of the
373 374 375
    /// allocation failure.
    ///
    /// @param query client's message (typically SOLICIT or REQUEST)
376
    /// @param answer server's response to the client's message (unused).
377
    /// @param ctx client context (contains subnet, duid and other parameters)
378 379
    /// @param ia pointer to client's IA_PD option (client's request)
    /// @return IA_PD option (server's response)
380
    OptionPtr assignIA_PD(const Pkt6Ptr& query,
381
                          const isc::dhcp::Pkt6Ptr& answer,
382
                          AllocEngine::ClientContext6& ctx,
383 384
                          boost::shared_ptr<Option6IA> ia);

385
    /// @brief Extends lifetime of the specific IA_NA option.
386
    ///
387 388 389 390
    /// Generates response to IA_NA in Renew or Rebind. This typically includes
    /// finding a lease that corresponds to the received address. If no such
    /// lease is found, an IA_NA response is generated with an appropriate
    /// status code.
391
    ///
392 393 394 395 396 397 398 399 400 401 402 403
    /// @todo The behavior of this function will need to be extended to support
    /// draft-ietf-dhc-dhcpv6-stateful-issues. This draft modifies the behavior
    /// described in RFC3315 with respect to Renew and Rebind processing. Key
    /// changes are (version -05):
    /// - Renewing and Rebinding client MAY request additional bindings by
    /// putting an IA for all bindings it desires but has been unable to obtain.
    /// Server MAY allocate addresses if it finds that they are appropriate for
    /// the link that client is attached to.
    /// - When receiving Rebind, if the server determines that the addresses are
    /// not appropriate for the link the client is attached to, the server MAY
    /// send the IA with address lifetimes set to 0 or discard the message.
    ///
404
    /// @param query client's message (Renew or Rebind)
405 406 407
    /// @param answer server's response to the client's message. This
    /// message should contain Client FQDN option being sent by the server
    /// to the client (if the client sent this option to the server).
408
    /// @param ctx client context (contains subnet, duid and other parameters)
Francis Dupont's avatar
Francis Dupont committed
409
    /// @param ia IA_NA option which carries address for which lease lifetime
410
    /// will be extended.
411
    /// @return IA_NA option (server's response)
412
    OptionPtr extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer,
413
                          AllocEngine::ClientContext6& ctx,
414
                          Option6IAPtr ia);
415

416 417 418 419
    /// @brief Extends lifetime of the prefix.
    ///
    /// This function is called by the logic which processes Renew and Rebind
    /// messages to extend the lifetime of the existing prefix.
420
    ///
421 422 423 424 425
    /// The behavior of this function is different in that when there is no
    /// binding found in the lease database for the particular client the
    /// NoBinding status code is returned when processing Renew, the exception
    /// is thrown when there is no binding and the Rebind message is processed
    /// (see RFC3633, section 12.2. for details).
426 427
    ///
    /// @param query client's message
428
    /// @param ctx client context (contains subnet, duid and other parameters)
429 430
    /// @param ia IA_PD option that is being renewed
    /// @return IA_PD option (server's response)
431 432 433
    /// @throw DHCPv6DiscardMessageError when the message being processed should
    /// be discarded by the server, i.e. there is no binding for the client doing
    /// Rebind.
434
    OptionPtr extendIA_PD(const Pkt6Ptr& query,
435
                          AllocEngine::ClientContext6& ctx,
436
                          Option6IAPtr ia);
437

438 439 440 441 442 443 444
    /// @brief Releases specific IA_NA option
    ///
    /// Generates response to IA_NA in Release message. This covers finding and
    /// removal of a lease that corresponds to the received address. If no such
    /// lease is found, an IA_NA response is generated with an appropriate
    /// status code.
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
445 446 447 448
    /// As RFC 3315 requires that a single status code be sent for the whole message,
    /// this method may update the passed general_status: it is set to SUCCESS when
    /// message processing begins, but may be updated to some error code if the
    /// release process fails.
449 450
    ///
    /// @param duid client's duid
451
    /// @param query client's message
452
    /// @param general_status a global status (it may be updated in case of errors)
453
    /// @param ia IA_NA option that is being released
454
    /// @param old_lease a pointer to the lease being released
455
    /// @return IA_NA option (server's response)
456
    OptionPtr releaseIA_NA(const DuidPtr& duid, const Pkt6Ptr& query,
457
                           int& general_status,
458 459
                           boost::shared_ptr<Option6IA> ia,
                           Lease6Ptr& old_lease);
460

461 462 463 464 465 466 467 468 469 470 471
    /// @brief Releases specific IA_PD option
    ///
    /// Generates response to IA_PD in Release message. This covers finding and
    /// removal of a lease that corresponds to the received prefix(es). If no such
    /// lease is found, an IA_PD response is generated with an appropriate
    /// status code.
    ///
    /// @param duid client's duid
    /// @param query client's message
    /// @param general_status a global status (it may be updated in case of errors)
    /// @param ia IA_PD option that is being released
472
    /// @param old_lease a pointer to the lease being released
473 474 475
    /// @return IA_PD option (server's response)
    OptionPtr releaseIA_PD(const DuidPtr& duid, const Pkt6Ptr& query,
                           int& general_status,
476 477
                           boost::shared_ptr<Option6IA> ia,
                           Lease6Ptr& old_lease);
478

Tomek Mrugalski's avatar
Tomek Mrugalski committed
479
    /// @brief Copies required options from client message to server answer.
480 481 482 483
    ///
    /// Copies options that must appear in any server response (ADVERTISE, REPLY)
    /// to client's messages (SOLICIT, REQUEST, RENEW, REBIND, DECLINE, RELEASE).
    /// One notable example is client-id. Other options may be copied as required.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
484
    /// Relay information details are also copied here.
485 486 487
    ///
    /// @param question client's message (options will be copied from here)
    /// @param answer server's message (options will be copied here)
Tomek Mrugalski's avatar
Tomek Mrugalski committed
488
    void copyClientOptions(const Pkt6Ptr& question, Pkt6Ptr& answer);
489

490 491 492 493 494
    /// @brief Build the configured option list
    ///
    /// @note The configured option list is an *ordered* list of
    /// @c CfgOption objects used to append options to the response.
    ///
495 496 497
    /// @param question client's message
    /// @param ctx client context (for the subnet)
    /// @param co_list configured option list to build
498
    void buildCfgOptionList(const Pkt6Ptr& question,
499 500
                            AllocEngine::ClientContext6& ctx,
                            CfgOptionList& co_list);
501

502 503 504 505 506 507 508 509
    /// @brief Appends default options to server's answer.
    ///
    /// Adds required options to server's answer. In particular, server-id
    /// is added. Possibly other mandatory options will be added, depending
    /// on type (or content) of client message.
    ///
    /// @param question client's message
    /// @param answer server's message (options will be added here)
510 511 512
    /// @param co_list configured option list (currently unused)
    void appendDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
                              const CfgOptionList& co_list);
513 514 515 516 517 518 519

    /// @brief Appends requested options to server's answer.
    ///
    /// Appends options requested by client to the server's answer.
    ///
    /// @param question client's message
    /// @param answer server's message (options will be added here)
520
    ///
521
    /// @param co_list configured option list
522
    void appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
523
                                const CfgOptionList& co_list);
524

525 526 527 528 529 530 531
    /// @brief Appends requested vendor options to server's answer.
    ///
    /// This is mostly useful for Cable Labs options for now, but the method
    /// is easily extensible to other vendors.
    ///
    /// @param question client's message
    /// @param answer server's message (vendor options will be added here)
532
    /// @param ctx client context (contains subnet, duid and other parameters)
533
    /// @param co_list configured option list
534
    void appendRequestedVendorOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
535 536
                                      AllocEngine::ClientContext6& ctx,
                                      const CfgOptionList& co_list);
537 538 539

    /// @brief Assigns leases.
    ///
540 541
    /// It supports non-temporary addresses (IA_NA) and prefixes (IA_PD). It
    /// does NOT support temporary addresses (IA_TA).
542
    ///
543 544 545 546 547 548
    /// @param question client's message (with requested IA options)
    /// @param answer server's message (IA options will be added here).
    ///   This message should contain Client FQDN option being sent by the server
    ///   to the client (if the client sent this option to the server).
    /// @param ctx client context (contains subnet, duid and other parameters)
    void assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer,
549
                      AllocEngine::ClientContext6& ctx);
550

551 552 553 554 555 556 557
    /// @brief Processes Client FQDN Option.
    ///
    /// This function retrieves DHCPv6 Client FQDN %Option (if any) from the
    /// packet sent by a client and takes necessary actions upon this option.
    /// Received option comprises flags field which controls what DNS updates
    /// server should do. Server may override client's preference based on
    /// the current configuration. Server indicates that it has overridden
558
    /// the preference by storing DHCPv6 Client FQDN option with the
559 560 561 562 563 564
    /// appropriate flags in the response to a client. This option is also
    /// used to communicate the client's domain-name which should be sent
    /// to the DNS in the update. Again, server may act upon the received
    /// domain-name, i.e. if the provided domain-name is partial it should
    /// generate the fully qualified domain-name.
    ///
565 566 567 568 569 570 571 572 573
    /// This function takes into account the host reservation if one is matched
    /// to this client when forming the FQDN to be used with DNS as well as the
    /// lease name to be stored with the lease. In the following the term
    /// "reserved hostname" means a host reservation which includes a
    /// non-blank hostname.
    ///
    /// - If there is no Client FQDN and no reserved hostname then there
    /// will no be DNS updates and the lease hostname will be empty.
    ///
Francis Dupont's avatar
Francis Dupont committed
574
    /// - If there is no Client FQDN but there is reserved hostname then
575
    /// there will be no DNS updates and the lease hostname will be equal
576
    /// to reserved hostname.
577 578 579 580 581
    ///
    /// - If there is a Client FQDN and a reserved hostname, then both the
    /// FQDN and lease hostname will be equal to reserved hostname with
    /// the qualifying suffix appended.
    ///
Francis Dupont's avatar
Francis Dupont committed
582
    /// - If there is a Client FQDN but no reserved hostname then both the
583 584 585 586
    /// FQDN and lease hostname will be equal to the name provided in the
    /// client FQDN adjusted according the the DhcpDdns configuration
    /// parameters (e.g.replace-client-name, qualifying suffix...).
    ///
587 588 589 590
    /// All the logic required to form appropriate answer to the client is
    /// held in this function.
    ///
    /// @param question Client's message.
591 592 593
    /// @param answer Server's response to a client. If server generated
    /// Client FQDN option for the client, this option is stored in this
    /// object.
594 595
    /// @param ctx client context (includes subnet, client-id, hw-addr etc.)
    void processClientFqdn(const Pkt6Ptr& question, const Pkt6Ptr& answer,
596
                           AllocEngine::ClientContext6& ctx);
597

598 599
    /// @brief Creates a number of @c isc::dhcp_ddns::NameChangeRequest objects
    /// based on the DHCPv6 Client FQDN %Option.
600
    ///
601 602 603
    /// The @c isc::dhcp_ddns::NameChangeRequest class encapsulates the request
    /// from the DHCPv6 server to the DHCP-DDNS module to perform DNS Update.
    /// The FQDN option carries response to the client about DNS updates that
Shawn Routhier's avatar
Shawn Routhier committed
604
    /// server intends to perform for the DNS client. Based on this, the
605 606
    /// function will create zero or more @c isc::dhcp_ddns::NameChangeRequest
    /// objects and store them in the internal queue. Requests created by this
Shawn Routhier's avatar
Shawn Routhier committed
607
    /// function are only for adding or updating DNS records. If DNS updates are
608
    /// disabled, this method returns immediately.
609
    ///
610 611
    /// @todo Add support for multiple IAADDR options in the IA_NA.
    ///
Francis Dupont's avatar
Francis Dupont committed
612
    /// @param answer A message begins sent to the Client. If it holds the
613
    /// @param ctx client context (contains subnet, duid and other parameters)
614
    /// Client FQDN option, this option is used to create NameChangeRequests.
615 616
    void createNameChangeRequests(const Pkt6Ptr& answer,
                                  AllocEngine::ClientContext6& ctx);
617

618 619 620 621 622 623 624
    /// @brief Attempts to extend the lifetime of IAs.
    ///
    /// This function is called when a client sends Renew or Rebind message.
    /// It iterates through received IA options and attempts to extend
    /// corresponding lease lifetimes. Internally, it calls
    /// @c Dhcpv6Srv::extendIA_NA and @c Dhcpv6Srv::extendIA_PD to extend
    /// the lifetime of IA_NA and IA_PD leases accordingly.
625
    ///
626
    /// @param query client's Renew or Rebind message
627
    /// @param reply server's response
628 629 630
    /// @param ctx client context (contains subnet, duid and other parameters)
    void extendLeases(const Pkt6Ptr& query, Pkt6Ptr& reply,
                      AllocEngine::ClientContext6& ctx);
631

632 633 634 635 636 637 638 639 640
    /// @brief Attempts to release received addresses
    ///
    /// It iterates through received IA_NA options and attempts to release
    /// received addresses. If no such leases are found, or the lease fails
    /// proper checks (e.g. belongs to someone else), a proper status
    /// code is added to reply message. Released addresses are not added
    /// to REPLY packet, just its IA_NA containers.
    /// @param release client's message asking to release
    /// @param reply server's response
641 642 643
    /// @param ctx client context (includes subnet, client-id, hw-addr etc.)
    void releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply,
                       AllocEngine::ClientContext6& ctx);
644

645 646 647 648 649 650 651
    /// @brief converts DUID to text
    /// Converts content of DUID option to a text representation, e.g.
    /// 01:ff:02:03:06:80:90:ab:cd:ef
    ///
    /// @param opt option that contains DUID
    /// @return string representation
    static std::string duidToString(const OptionPtr& opt);
652

653 654 655 656 657 658
    /// @brief dummy wrapper around IfaceMgr::receive6
    ///
    /// This method is useful for testing purposes, where its replacement
    /// simulates reception of a packet. For that purpose it is protected.
    virtual Pkt6Ptr receivePacket(int timeout);

659 660 661
    /// @brief dummy wrapper around IfaceMgr::send()
    ///
    /// This method is useful for testing purposes, where its replacement
Tomek Mrugalski's avatar
Tomek Mrugalski committed
662
    /// simulates transmission of a packet. For that purpose it is protected.
663 664
    virtual void sendPacket(const Pkt6Ptr& pkt);

665 666
    /// @brief Assigns incoming packet to zero or more classes.
    ///
667 668 669 670 671
    /// @note This is done in two phases: first the content of the
    /// vendor-class-identifier option is used as a class, by
    /// calling @ref classifyByVendor(). Second classification match
    /// expressions are evaluated. The resulting classes will be stored
    /// in the packet (see @ref isc::dhcp::Pkt6::classes_ and
672 673 674 675 676
    /// @ref isc::dhcp::Pkt6::inClass).
    ///
    /// @param pkt packet to be classified
    void classifyPacket(const Pkt6Ptr& pkt);

677 678 679 680 681 682 683
    /// @brief Assigns classes retrieved from host reservation database.
    ///
    /// @param pkt Pointer to the packet to which classes will be assigned.
    /// @param ctx Reference to the client context.
    void setReservedClientClasses(const Pkt6Ptr& pkt,
                                  const AllocEngine::ClientContext6& ctx);

684
    /// @brief Assigns incoming packet to zero or more classes (required pass).
685
    ///
686 687 688
    /// @note This required classification evaluates all classes which
    /// were marked for required evaluation. Classes are collected so
    /// evaluated in the reversed order than output option processing.
689
    ///
690
    /// @note The only-if-required flag is related because it avoids
691 692 693 694
    /// double evaluation (which is not forbidden).
    ///
    /// @param pkt packet to be classified
    /// @param ctx allocation context where to get informations
695
    void requiredClassify(const Pkt6Ptr& pkt, AllocEngine::ClientContext6& ctx);
696

Josh Soref's avatar
Josh Soref committed
697
    /// @brief Attempts to get a MAC/hardware address using configured sources
Tomek Mrugalski's avatar
Tomek Mrugalski committed
698 699
    ///
    /// Tries to extract MAC/hardware address information from the packet
Tomek Mrugalski's avatar
Tomek Mrugalski committed
700
    /// using MAC sources configured in 'mac-sources' configuration parameter.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
701 702 703
    ///
    /// @param pkt will try to exact MAC address from this packet
    /// @return HWaddr pointer (or NULL if configured methods fail)
Tomek Mrugalski's avatar
Tomek Mrugalski committed
704
    static HWAddrPtr getMAC(const Pkt6Ptr& pkt);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
705

706 707 708 709
    /// @brief Processes Relay-supplied options, if present
    ///
    /// This method implements RFC6422. It checks if there are any RSOO options
    /// inserted by the relay agents in the query message. If there are, they
710
    /// are copied over to the response if they meet the following criteria:
711 712 713 714 715
    /// - the option is marked as RSOO-enabled (see relay-supplied-options
    ///   configuration parameter)
    /// - there is no such option provided by the server)
    void processRSOO(const Pkt6Ptr& query, const Pkt6Ptr& rsp);

716
    /// @brief Initializes client context for specified packet
717
    ///
718
    /// This method:
719 720 721 722 723 724 725
    /// - Performs the subnet selection and stores the result in context
    /// - Extracts the duid from the packet and saves it to the context
    /// - Extracts the hardware address from the packet and saves it to
    /// the context
    /// - Performs host reservation lookup and stores the result in the
    /// context
    ///
726 727 728 729 730 731 732
    /// Even though the incoming packet type is known to this method, it
    /// doesn't set the @c fake_allocation flag, because of a possibility
    /// that the Rapid Commit option is in use. The @c fake_allocation
    /// flag is set appropriately after it has been determined whether
    /// the Rapid Commit option was included and that the server respects
    /// it.
    ///
733 734
    /// @param pkt pointer to a packet for which context will be created.
    /// @param [out] ctx reference to context object to be initialized.
735 736 737 738
    /// @param [out] drop if it is true the packet will be dropped.
    void initContext(const Pkt6Ptr& pkt,
                     AllocEngine::ClientContext6& ctx,
                     bool& drop);
739

Josh Soref's avatar
Josh Soref committed
740
    /// @brief this is a prefix added to the content of vendor-class option
741 742 743 744 745 746 747
    ///
    /// If incoming packet has a vendor class option, its content is
    /// prepended with this prefix and then interpreted as a class.
    /// For example, a packet that sends vendor class with value of "FOO"
    /// will cause the packet to be assigned to class VENDOR_CLASS_FOO.
    static const std::string VENDOR_CLASS_PREFIX;

748 749 750 751 752
    /// @brief Attempts to decline all leases in specified Decline message.
    ///
    /// This method iterates over all IA_NA options and calls @ref declineIA on
    /// each of them.
    ///
Francis Dupont's avatar
Francis Dupont committed
753
    /// @param decline Decline message sent by a client
754
    /// @param reply Server's response (IA_NA with status will be added here)
755
    /// @param ctx context
756 757 758 759
    /// @return true when expected to continue, false when hooks told us to drop
    ///         the packet
    bool declineLeases(const Pkt6Ptr& decline, Pkt6Ptr& reply,
                       AllocEngine::ClientContext6& ctx);
760

Tomek Mrugalski's avatar
Tomek Mrugalski committed
761
    /// @brief Declines leases in a single IA_NA option
762
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
763 764
    /// This method iterates over all addresses in this IA_NA, verifies
    /// whether they belong to the client and calls @ref declineLease. If there's
765 766 767 768 769 770 771
    /// an error, general_status (a status put in the top level scope), will be
    /// updated.
    ///
    /// @param decline client's Decline message
    /// @param duid client's duid (used to verify if the client owns the lease)
    /// @param general_status [out] status in top-level message (may be updated)
    /// @param ia specific IA_NA option to process.
772
    /// @param new_leases a collection of leases being declined.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
773
    /// @return IA_NA option with response (to be included in Reply message)
774 775
    OptionPtr
    declineIA(const Pkt6Ptr& decline, const DuidPtr& duid, int& general_status,
776
              boost::shared_ptr<Option6IA> ia, Lease6Collection& new_leases);
777 778 779 780 781

    /// @brief Declines specific IPv6 lease.
    ///
    /// This method performs the actual decline and all necessary operations:
    /// - cleans up DNS, if necessary
Tomek Mrugalski's avatar
Tomek Mrugalski committed
782 783
    /// - updates subnet[X].declined-addresses (per subnet stat)
    /// - updates declined-addresses (global stat)
Francis Dupont's avatar
Francis Dupont committed
784
    /// - disassociates client information from the lease
785 786 787 788 789 790 791
    /// - moves the lease to DECLINED state
    /// - sets lease expiration time to decline-probation-period
    /// - adds status-code success
    ///
    /// @param decline used for generating removal Name Change Request.
    /// @param lease lease to be declined
    /// @param ia_rsp response IA_NA.
792 793 794 795
    /// @return true when expected to continue, false when hooks told us to drop
    ///         the packet
    bool declineLease(const Pkt6Ptr& decline, const Lease6Ptr lease,
                      boost::shared_ptr<Option6IA> ia_rsp);
796 797 798 799 800 801 802 803 804

    /// @brief A simple utility method that sets the status code
    ///
    /// Removes old status code and sets a new one.
    /// @param container status code will be added here
    /// @param status status code option
    void setStatusCode(boost::shared_ptr<Option6IA>& container,
                       const OptionPtr& status);

805 806 807 808
public:

    /// Used for DHCPv4-over-DHCPv6 too.

809 810 811 812
    /// @brief Check if the last relay added a relay-source-port option.
    ///
    /// @param query DHCPv6 message to be checked.
    /// @return the port to use to join the relay or 0 for the default.
813
    static uint16_t checkRelaySourcePort(const Pkt6Ptr& query);
814

815
private:
816

Francis Dupont's avatar
Francis Dupont committed
817
    /// @public
818 819 820 821 822 823 824 825
    /// @brief Assign class using vendor-class-identifier option
    ///
    /// @note This is the first part of @ref classifyPacket
    ///
    /// @param pkt packet to be classified
    /// @param classes a reference to added class names for logging
    void classifyByVendor(const Pkt6Ptr& pkt, std::string& classes);

826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
    /// @brief Update FQDN based on the reservations in the current subnet.
    ///
    /// When shared networks are in use the allocation engine may switch to
    /// a different subnet than originally selected. If this new subnet has
    /// hostname reservations there is a need to update the FQDN option
    /// value.
    ///
    /// This method should be called after lease assignments to perform
    /// such update when required.
    ///
    /// @param ctx Client context.
    /// @param answer Message being sent to a client, which may hold an FQDN
    /// option to be updated.
    ///
    /// @throw isc::Unexpected if specified message is NULL. This is treated
    /// as a programmatic error.
    void updateReservedFqdn(const AllocEngine::ClientContext6& ctx,
                            const Pkt6Ptr& answer);

Francis Dupont's avatar
Francis Dupont committed
845
    /// @private
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
    /// @brief Generate FQDN to be sent to a client if none exists.
    ///
    /// This function is meant to be called by the functions which process
    /// client's messages. The function should be called after a function
    /// which creates FQDN option for the client. This option must exist
    /// in the answer message specified as an argument. It must also be
    /// called after functions which assign leases for a client. The
    /// IA options being a result of lease acquisition must be appended
    /// to the message specified as a parameter.
    ///
    /// If the Client FQDN option being present in the message carries empty
    /// hostname, this function will attempt to generate hostname from the
    /// IPv6 address being acquired by the client. The IPv6 address is retrieved
    /// from the IA_NA option carried in the specified message. If multiple
    /// addresses are present in the particular IA_NA option or multiple IA_NA
    /// options exist, the first address found is selected.
    ///
    /// The IPv6 address is converted to the hostname using the following
    /// pattern:
    /// @code
    ///     prefix-converted-ip-address.domain-name-suffix.
    /// @endcode
    /// where:
    /// - prefix is a configurable prefix string appended to all auto-generated
    /// hostnames.
    /// - converted-ip-address is created by replacing all colons from the IPv6
    /// address with hyphens.
    /// - domain-name-suffix is a suffix for a domain name that, together with
    /// the other parts, constitute the fully qualified domain name.
    ///
    /// When hostname is successfully generated, it is either used to update
    /// FQDN-related fields in a lease database or to update the Client FQDN
    /// option being sent back to the client. The lease database update is
    /// NOT performed if Advertise message is being processed.
    ///
    /// @param answer Message being sent to a client, which may hold IA_NA
    /// and Client FQDN options to be used to generate name for a client.
    ///
    /// @throw isc::Unexpected if specified message is NULL. This is treated
    /// as a programmatic error.
    void generateFqdn(const Pkt6Ptr& answer);

888 889 890 891
    /// @brief Updates statistics for received packets
    /// @param query packet received
    static void processStatsReceived(const Pkt6Ptr& query);

892 893 894 895 896 897 898 899 900
    /// @brief Checks if the specified option code has been requested using
    /// the Option Request option.
    ///
    /// @param query Pointer to the client's query.
    /// @parma code Option code.
    ///
    /// @return true if option has been requested in the ORO.
    bool requestedInORO(const Pkt6Ptr& query, const uint16_t code) const;

901 902 903 904
    /// UDP port number on which server listens.
    uint16_t port_;

public:
Francis Dupont's avatar
Francis Dupont committed
905
    /// @note used by DHCPv4-over-DHCPv6 so must be public and static
906

907
    /// @brief Updates statistics for transmitted packets
Francis Dupont's avatar
Francis Dupont committed
908
    /// @param response packet transmitted
909 910
    static void processStatsSent(const Pkt6Ptr& response);

Francis Dupont's avatar
Francis Dupont committed
911 912 913
    /// @brief Returns the index of the buffer6_send hook
    /// @return the index of the buffer6_send hook
    static int getHookIndexBuffer6Send();
914

915 916 917 918 919 920 921
    /// @brief Executes buffer6_send callout and sends the response.
    ///
    /// @param callout_handle pointer to the callout handle.
    /// @param rsp pointer to a response.
    void processPacketBufferSend(hooks::CalloutHandlePtr& callout_handle,
                                 Pkt6Ptr& rsp);

922 923
protected:

924 925 926
    /// Server DUID (to be sent in server-identifier option)
    OptionPtr serverid_;

927 928 929 930
    /// Indicates if shutdown is in progress. Setting it to true will
    /// initiate server shutdown procedure.
    volatile bool shutdown_;

931 932 933 934 935 936 937 938
    /// @brief Executes pkt6_send callout.
    ///
    /// @param callout_handle pointer to the callout handle.
    /// @param query Pointer to a query.
    /// @param rsp Pointer to a response.
    void processPacketPktSend(hooks::CalloutHandlePtr& callout_handle,
                              Pkt6Ptr& query, Pkt6Ptr& rsp);

939 940 941 942 943