1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
|
// Copyright (C) 2011-2017 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef DHCPV6_SRV_H
#define DHCPV6_SRV_H
#include <asiolink/io_service.h>
#include <dhcp_ddns/ncr_msg.h>
#include <dhcp/dhcp6.h>
#include <dhcp/duid.h>
#include <dhcp/option.h>
#include <dhcp/option6_client_fqdn.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option_definition.h>
#include <dhcp/pkt6.h>
#include <dhcpsrv/alloc_engine.h>
#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/d2_client_mgr.h>
#include <dhcpsrv/subnet.h>
#include <hooks/callout_handle.h>
#include <dhcpsrv/daemon.h>
#include <iostream>
#include <queue>
// Undefine the macro OPTIONAL which is defined in some operating
// systems but conflicts with a member of the RequirementLevel enum in
// the server class.
#ifdef OPTIONAL
#undef OPTIONAL
#endif
namespace isc {
namespace dhcp {
/// @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) { };
};
/// @brief DHCPv6 server service.
///
/// This class represents DHCPv6 server. It contains all
/// 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.
class Dhcpv6Srv : public Daemon {
private:
/// @brief Pointer to IO service used by the server.
asiolink::IOServicePtr io_service_;
public:
/// @brief defines if certain option may, must or must not appear
typedef enum {
FORBIDDEN,
MANDATORY,
OPTIONAL
} RequirementLevel;
/// @brief Minimum length of a MAC address to be used in DUID generation.
static const size_t MIN_MAC_LEN = 6;
/// @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.
///
/// @param port port on will all sockets will listen
Dhcpv6Srv(uint16_t port = DHCP6_SERVER_PORT);
/// @brief Destructor. Used during DHCPv6 service shutdown.
virtual ~Dhcpv6Srv();
/// @brief Returns pointer to the IO service used by the server.
asiolink::IOServicePtr& getIOService() {
return (io_service_);
}
/// @brief returns Kea version on stdout and exit.
/// redeclaration/redefinition. @ref Daemon::getVersion()
static std::string getVersion(bool extended);
/// @brief Returns server-identifier option.
///
/// @return server-id option
OptionPtr getServerID() { return serverid_; }
/// @brief Main server processing loop.
///
/// Main server processing loop. Call the processing step routine
/// until shut down.
///
/// @return true, if being shut down gracefully, never fail.
bool run();
/// @brief Main server processing step.
///
/// Main server processing step. Receives one incoming packet, calls
/// the processing packet routing and (if necessary) transmits
/// a response.
void run_one();
/// @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
void processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp);
/// @brief Instructs the server to shut down.
void shutdown();
/// @brief Get UDP port on which server should listen.
///
/// Typically, server listens on UDP port 547. Other ports are only
/// used for testing purposes.
///
/// @return UDP port on which server should listen.
uint16_t getPort() const {
return (port_);
}
/// @brief Starts DHCP_DDNS client IO if DDNS updates are enabled.
///
/// If updates are enabled, it instructs the D2ClientMgr singleton to
/// enter send mode. If D2ClientMgr encounters errors it may throw
/// D2ClientError. This method does not catch exceptions.
void startD2();
/// @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
/// D2ClientError. This method does not catch exceptions.
void stopD2();
/// @brief Implements the error handler for DHCP_DDNS IO errors
///
/// Invoked when a NameChangeRequest send to kea-dhcp-ddns completes with
/// 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);
protected:
/// @brief Compare received server id with our server id
///
/// Checks if the server id carried in a query from a client matches
/// server identifier being used by the server.
///
/// @param pkt DHCPv6 packet carrying server identifier to be checked.
/// @return true if server id carried in the query matches server id
/// used by the server; false otherwise.
bool testServerID(const Pkt6Ptr& pkt);
/// @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;
/// @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);
/// @brief Processes incoming Solicit and returns response.
///
/// Processes received Solicit message and verifies that its sender
/// should be served. In particular IA, TA and PD options are populated
/// with to-be assigned addresses, temporary addresses and delegated
/// prefixes, respectively. In the usual 4 message exchange, server is
/// 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
/// immediately.
///
/// @param solicit Solicit message received from client
///
/// @return Advertise, Reply message or NULL.
Pkt6Ptr processSolicit(const Pkt6Ptr& solicit);
/// @brief Processes incoming Request and returns Reply response.
///
/// Processes incoming Request message and verifies that its sender
/// should be served. In particular IA, TA and PD options are populated
/// with assigned addresses, temporary addresses and delegated
/// prefixes, respectively. Uses LeaseMgr to allocate or update existing
/// leases.
///
/// @param request a message received from client
///
/// @return REPLY message or NULL
Pkt6Ptr processRequest(const Pkt6Ptr& request);
/// @brief Processes incoming Renew message.
///
/// @param renew message received from the client
/// @return Reply message to be sent to the client.
Pkt6Ptr processRenew(const Pkt6Ptr& renew);
/// @brief Processes incoming Rebind message.
///
/// @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.
///
/// @param rebind message received from the client.
/// @return Reply message to be sent to the client.
Pkt6Ptr processRebind(const Pkt6Ptr& rebind);
/// @brief Processes incoming Confirm message and returns Reply.
///
/// 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.
///
/// @param confirm Confirm message sent by a client.
///
/// @return Reply message from the server or NULL pointer if Confirm
/// message should be discarded by the server.
Pkt6Ptr processConfirm(const Pkt6Ptr& confirm);
/// @brief Process incoming Release message.
///
/// @param release message received from client
/// @return Reply message to be sent to the client.
Pkt6Ptr processRelease(const Pkt6Ptr& release);
/// @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.
///
/// @throw RFCViolation if Decline message is invalid (lacking mandatory
/// options)
///
/// @param decline message received from client
Pkt6Ptr processDecline(const Pkt6Ptr& decline);
/// @brief Processes incoming Information-request message.
///
/// @param inf_request message received from client
/// @return Reply message to be sent to the client.
Pkt6Ptr processInfRequest(const Pkt6Ptr& inf_request);
/// @brief Processes incoming DHCPv4-query message.
///
/// 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.
///
/// @param dhcp4_query message received from client
void processDhcp4Query(const Pkt6Ptr& dhcp4_query);
/// @brief Selects a subnet for a given client's packet.
///
/// @param question client's message
/// @return selected subnet (or NULL if no suitable subnet was found)
isc::dhcp::Subnet6Ptr selectSubnet(const Pkt6Ptr& question);
/// @brief Processes IA_NA option (and assigns addresses if necessary).
///
/// Generates response to IA_NA. This typically includes selecting (and
/// allocating a lease in case of REQUEST) an address lease and creating
/// IAADDR option. In case of allocation failure, it may contain
/// status code option with non-zero status, denoting cause of the
/// allocation failure.
///
/// @param query client's message (typically SOLICIT or REQUEST)
/// @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).
/// @param ctx client context (contains subnet, duid and other parameters)
/// @param ia pointer to client's IA_NA option (client's request)
///
/// @return IA_NA option (server's response)
OptionPtr assignIA_NA(const isc::dhcp::Pkt6Ptr& query,
const isc::dhcp::Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx,
Option6IAPtr ia);
/// @brief Processes IA_PD option (and assigns prefixes if necessary).
///
/// Generates response to IA_PD. This typically includes selecting (and
/// 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
/// allocation failure.
///
/// @param query client's message (typically SOLICIT or REQUEST)
/// @param answer server's response to the client's message.
/// @param ctx client context (contains subnet, duid and other parameters)
/// @param ia pointer to client's IA_PD option (client's request)
/// @return IA_PD option (server's response)
OptionPtr assignIA_PD(const Pkt6Ptr& query,
const isc::dhcp::Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx,
boost::shared_ptr<Option6IA> ia);
/// @brief Extends lifetime of the specific IA_NA option.
///
/// 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.
///
/// @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.
///
/// @param query client's message (Renew or Rebind)
/// @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).
/// @param ctx client context (contains subnet, duid and other parameters)
/// @param ia IA_NA option which carries address for which lease lifetime
/// will be extended.
/// @return IA_NA option (server's response)
OptionPtr extendIA_NA(const Pkt6Ptr& query, const Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx,
Option6IAPtr ia);
/// @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.
///
/// 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).
///
/// @param query client's message
/// @param ctx client context (contains subnet, duid and other parameters)
/// @param ia IA_PD option that is being renewed
/// @return IA_PD option (server's response)
/// @throw DHCPv6DiscardMessageError when the message being processed should
/// be discarded by the server, i.e. there is no binding for the client doing
/// Rebind.
OptionPtr extendIA_PD(const Pkt6Ptr& query,
AllocEngine::ClientContext6& ctx,
Option6IAPtr ia);
/// @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.
///
/// 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.
///
/// @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_NA option that is being released
/// @return IA_NA option (server's response)
OptionPtr releaseIA_NA(const DuidPtr& duid, const Pkt6Ptr& query,
int& general_status,
boost::shared_ptr<Option6IA> ia);
/// @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
/// @return IA_PD option (server's response)
OptionPtr releaseIA_PD(const DuidPtr& duid, const Pkt6Ptr& query,
int& general_status,
boost::shared_ptr<Option6IA> ia);
/// @brief Copies required options from client message to server answer.
///
/// 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.
/// Relay information details are also copied here.
///
/// @param question client's message (options will be copied from here)
/// @param answer server's message (options will be copied here)
void copyClientOptions(const Pkt6Ptr& question, Pkt6Ptr& answer);
/// @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.
///
/// @param question client's message
/// @param ctx client context (for the subnet)
/// @param co_list configured option list to build
void buildCfgOptionList(const Pkt6Ptr& question,
AllocEngine::ClientContext6& ctx,
CfgOptionList& co_list);
/// @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)
/// @param co_list configured option list (currently unused)
void appendDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
const CfgOptionList& co_list);
/// @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)
///
/// @param co_list configured option list
void appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
const CfgOptionList& co_list);
/// @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)
/// @param ctx client context (contains subnet, duid and other parameters)
/// @param co_list configured option list
void appendRequestedVendorOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx,
const CfgOptionList& co_list);
/// @brief Assigns leases.
///
/// It supports non-temporary addresses (IA_NA) and prefixes (IA_PD). It
/// does NOT support temporary addresses (IA_TA).
///
/// @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,
AllocEngine::ClientContext6& ctx);
/// @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
/// the preference by storing DHCPv6 Client FQDN option with the
/// 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.
///
/// 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.
///
/// - If there is no Client FQDN but there is reserved hostname then
/// there will be no DNS updates and the lease hostname will be equal
/// to reserved hostname.
///
/// - 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.
///
/// - If there is a Client FQDN but no reserved hostname then both the
/// 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...).
///
/// All the logic required to form appropriate answer to the client is
/// held in this function.
///
/// @param question Client's message.
/// @param answer Server's response to a client. If server generated
/// Client FQDN option for the client, this option is stored in this
/// object.
/// @param ctx client context (includes subnet, client-id, hw-addr etc.)
void processClientFqdn(const Pkt6Ptr& question, const Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx);
/// @brief Creates a number of @c isc::dhcp_ddns::NameChangeRequest objects
/// based on the DHCPv6 Client FQDN %Option.
///
/// 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
/// server intends to perform for the DNS client. Based on this, the
/// function will create zero or more @c isc::dhcp_ddns::NameChangeRequest
/// objects and store them in the internal queue. Requests created by this
/// function are only for adding or updating DNS records. If DNS updates are
/// disabled, this method returns immediately.
///
/// @todo Add support for multiple IAADDR options in the IA_NA.
///
/// @param answer A message begins sent to the Client. If it holds the
/// @param ctx client context (contains subnet, duid and other parameters)
/// Client FQDN option, this option is used to create NameChangeRequests.
void createNameChangeRequests(const Pkt6Ptr& answer,
AllocEngine::ClientContext6& ctx);
/// @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.
///
/// @param query client's Renew or Rebind message
/// @param reply server's response
/// @param ctx client context (contains subnet, duid and other parameters)
void extendLeases(const Pkt6Ptr& query, Pkt6Ptr& reply,
AllocEngine::ClientContext6& ctx);
/// @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
/// @param ctx client context (includes subnet, client-id, hw-addr etc.)
void releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply,
AllocEngine::ClientContext6& ctx);
/// @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);
/// @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);
/// @brief dummy wrapper around IfaceMgr::send()
///
/// This method is useful for testing purposes, where its replacement
/// simulates transmission of a packet. For that purpose it is protected.
virtual void sendPacket(const Pkt6Ptr& pkt);
/// @brief Assigns incoming packet to zero or more classes.
///
/// @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
/// @ref isc::dhcp::Pkt6::inClass).
///
/// @param pkt packet to be classified
void classifyPacket(const Pkt6Ptr& pkt);
/// @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);
/// @brief Attempts to get a MAC/hardware address using configured sources
///
/// Tries to extract MAC/hardware address information from the packet
/// using MAC sources configured in 'mac-sources' configuration parameter.
///
/// @param pkt will try to exact MAC address from this packet
/// @return HWaddr pointer (or NULL if configured methods fail)
static HWAddrPtr getMAC(const Pkt6Ptr& pkt);
/// @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
/// are copied over to the response if they meet the following criteria:
/// - 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);
/// @brief Initializes client context for specified packet
///
/// This method:
/// - 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
///
/// 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.
///
/// @param pkt pointer to a packet for which context will be created.
/// @param [out] ctx reference to context object to be initialized.
void initContext(const Pkt6Ptr& pkt, AllocEngine::ClientContext6& ctx);
/// @brief this is a prefix added to the content of vendor-class option
///
/// 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;
/// @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.
///
/// @param decline Decline message sent by a client
/// @param reply Server's response (IA_NA with status will be added here)
/// @param ctx context
/// @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);
/// @brief Declines leases in a single IA_NA option
///
/// This method iterates over all addresses in this IA_NA, verifies
/// whether they belong to the client and calls @ref declineLease. If there's
/// 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.
/// @return IA_NA option with response (to be included in Reply message)
OptionPtr
declineIA(const Pkt6Ptr& decline, const DuidPtr& duid, int& general_status,
boost::shared_ptr<Option6IA> ia);
/// @brief Declines specific IPv6 lease.
///
/// This method performs the actual decline and all necessary operations:
/// - cleans up DNS, if necessary
/// - updates subnet[X].declined-addresses (per subnet stat)
/// - updates declined-addresses (global stat)
/// - disassociates client information from the lease
/// - 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.
/// @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);
/// @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);
private:
/// @public
/// @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);
/// @private
/// @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);
/// @brief Updates statistics for received packets
/// @param query packet received
static void processStatsReceived(const Pkt6Ptr& query);
/// @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;
/// UDP port number on which server listens.
uint16_t port_;
public:
/// @note used by DHCPv4-over-DHCPv6 so must be public and static
/// @brief Updates statistics for transmitted packets
/// @param response packet transmitted
static void processStatsSent(const Pkt6Ptr& response);
/// @brief Returns the index of the buffer6_send hook
/// @return the index of the buffer6_send hook
static int getHookIndexBuffer6Send();
protected:
/// Server DUID (to be sent in server-identifier option)
OptionPtr serverid_;
/// Indicates if shutdown is in progress. Setting it to true will
/// initiate server shutdown procedure.
volatile bool shutdown_;
/// @brief Allocation Engine.
/// Pointer to the allocation engine that we are currently using
/// It must be a pointer, because we will support changing engines
/// during normal operation (e.g. to use different allocators)
boost::shared_ptr<AllocEngine> alloc_engine_;
/// Holds a list of @c isc::dhcp_ddns::NameChangeRequest objects, which
/// are waiting for sending to kea-dhcp-ddns module.
std::queue<isc::dhcp_ddns::NameChangeRequest> name_change_reqs_;
};
}; // namespace isc::dhcp
}; // namespace isc
#endif // DHCP6_SRV_H
|