dhcp4_srv.h 32.8 KB
Newer Older
1
// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

#ifndef DHCPV4_SRV_H
#define DHCPV4_SRV_H

18
#include <dhcp/dhcp4.h>
19
20
#include <dhcp/pkt4.h>
#include <dhcp/option.h>
21
#include <dhcp/option_string.h>
22
#include <dhcp/option4_client_fqdn.h>
23
#include <dhcp/option_custom.h>
24
#include <dhcp_ddns/ncr_msg.h>
25
#include <dhcpsrv/d2_client_mgr.h>
26
27
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/alloc_engine.h>
28
#include <hooks/callout_handle.h>
29
#include <dhcpsrv/daemon.h>
30
31
32

#include <boost/noncopyable.hpp>

33
#include <iostream>
34
#include <queue>
35
36
37

namespace isc {
namespace dhcp {
38

39
40
41
42
43
44
45
/// @brief Exception thrown when DHCID computation failed.
class DhcidComputeError : public isc::Exception {
public:
    DhcidComputeError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

46
47
48
49
50
/// @brief DHCPv4 message exchange.
///
/// This class represents the DHCPv4 message exchange. The message exchange
/// consists of the single client message, server response to this message
/// and the mechanisms to generate the server's response. The server creates
51
/// the instance of the @c Dhcpv4Exchange for each inbound message that it
52
53
/// accepts for processing.
///
54
/// The use of the @c Dhcpv4Exchange object as a central repository of
55
56
57
58
59
60
61
62
63
64
/// information about the message exchange simplifies the API of the
/// @c Dhcpv4Srv class.
///
/// Another benefit of using this class is that different methods of the
/// @c Dhcpv4Srv may share information. For example, the constructor of this
/// class selects the subnet and multiple methods of @c Dhcpv4Srv use this
/// subnet, without the need to select it again.
///
/// @todo This is the initial version of this class. In the future a lot of
/// code from the @c Dhcpv4Srv class will be migrated here.
65
class Dhcpv4Exchange {
66
67
68
69
70
71
72
73
74
75
76
77
public:
    /// @brief Constructor.
    ///
    /// The constructor selects the subnet for the query and checks for the
    /// static host reservations for the client which has sent the message.
    /// The information about the reservations is stored in the
    /// @c AllocEngine::ClientContext4 object, which can be obtained by
    /// calling the @c getContext.
    ///
    /// @param alloc_engine Pointer to the instance of the Allocation Engine
    /// used by the server.
    /// @param query Pointer to the client message.
78
79
80
    /// @param subnet Pointer to the subnet to which the client belongs.
    Dhcpv4Exchange(const AllocEnginePtr& alloc_engine, const Pkt4Ptr& query,
                   const Subnet4Ptr& subnet);
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

    /// @brief Initializes the instance of the response message.
    ///
    /// The type of the response depends on the type of the query message.
    /// For the DHCPDISCOVER the DHCPOFFER is created. For the DHCPREQUEST
    /// and DHCPINFORM the DHCPACK is created. For the DHCPRELEASE the
    /// response is not initialized.
    void initResponse();

    /// @brief Returns the pointer to the query from the client.
    Pkt4Ptr getQuery() const {
        return (query_);
    }

    /// @brief Returns the pointer to the server's response.
    ///
    /// The returned pointer is NULL if the query type is DHCPRELEASE or DHCPDECLINE.
    Pkt4Ptr getResponse() const {
        return (resp_);
    }

    /// @brief Removes the response message by resetting the pointer to NULL.
    void deleteResponse() {
        resp_.reset();
    }

    /// @brief Returns the copy of the context for the Allocation engine.
    AllocEngine::ClientContext4Ptr getContext() const {
        return (context_);
    }

private:
113
114
115
116
117
118
119
120
121
122
123
124

    /// @brief Copies default parameters from client's to server's message
    ///
    /// Some fields are copied from client's message into server's response,
    /// e.g. client HW address, number of hops, transaction-id etc.
    ///
    /// @warning This message is called internally by @c initResponse and
    /// thus it doesn't check if the resp_ value has been initialized. The
    /// calling method is responsible for making sure that @c resp_ is
    /// not NULL.
    void copyDefaultFields();

125
126
127
128
129
130
131
132
133
134
    /// @brief Pointer to the allocation engine used by the server.
    AllocEnginePtr alloc_engine_;
    /// @brief Pointer to the DHCPv4 message sent by the client.
    Pkt4Ptr query_;
    /// @brief Pointer to the DHCPv4 message to be sent to the client.
    Pkt4Ptr resp_;
    /// @brief Context for use with allocation engine.
    AllocEngine::ClientContext4Ptr context_;
};

135
136
/// @brief Type representing the pointer to the @c Dhcpv4Exchange.
typedef boost::shared_ptr<Dhcpv4Exchange> Dhcpv4ExchangePtr;
137
138


139
140
141
142
143
144
145
146
/// @brief DHCPv4 server service.
///
/// This singleton class represents DHCPv4 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.
147
148
///
/// This class does not support any controlling mechanisms directly.
149
/// See the derived \ref ControlledDhcpv4Srv class for support for
150
151
152
153
/// command and configuration updates over msgq.
///
/// For detailed explanation or relations between main(), ControlledDhcpv4Srv,
/// Dhcpv4Srv and other classes, see \ref dhcpv4Session.
154
class Dhcpv4Srv : public Daemon {
155

156
public:
157
158
159
160
161
162
163
164

    /// @brief defines if certain option may, must or must not appear
    typedef enum {
        FORBIDDEN,
        MANDATORY,
        OPTIONAL
    } RequirementLevel;

165
166
    /// @brief Default constructor.
    ///
167
    /// Instantiates necessary services, required to run DHCPv4 server.
168
169
    /// In particular, creates IfaceMgr that will be responsible for
    /// network interaction. Will instantiate lease manager, and load
Tomek Mrugalski's avatar
Tomek Mrugalski committed
170
171
    /// old or create new DUID. It is possible to specify alternate
    /// port on which DHCPv4 server will listen on. That is mostly useful
172
173
    /// for testing purposes. The Last two arguments of the constructor
    /// should be left at default values for normal server operation.
Marcin Siodelski's avatar
Marcin Siodelski committed
174
175
176
    /// They should be set to 'false' when creating an instance of this
    /// class for unit testing because features they enable require
    /// root privileges.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
177
178
    ///
    /// @param port specifies port number to listen on
179
    /// @param use_bcast configure sockets to support broadcast messages.
180
181
    /// @param direct_response_desired specifies if it is desired to
    /// use direct V4 traffic.
182
    Dhcpv4Srv(uint16_t port = DHCP4_SERVER_PORT,
183
184
              const bool use_bcast = true,
              const bool direct_response_desired = true);
185

186
    /// @brief Destructor. Used during DHCPv4 service shutdown.
187
    virtual ~Dhcpv4Srv();
188
189
190
191
192

    /// @brief Main server processing loop.
    ///
    /// Main server processing loop. Receives incoming packets, verifies
    /// their correctness, generates appropriate answer (if needed) and
Francis Dupont's avatar
Francis Dupont committed
193
    /// transmits responses.
194
195
196
197
198
    ///
    /// @return true, if being shut down gracefully, fail if experienced
    ///         critical error.
    bool run();

199
    /// @brief Instructs the server to shut down.
200
201
    void shutdown();

202
203
204
205
206
    /// @brief Return textual type of packet received by server
    ///
    /// Returns the name of valid packet received by the server (e.g. DISCOVER).
    /// If the packet is unknown - or if it is a valid DHCP packet but not one
    /// expected to be received by the server (such as an OFFER), the string
207
    /// "UNKNOWN" is returned.  This method is used in debug messages.
208
209
210
211
    ///
    /// As the operation of the method does not depend on any server state, it
    /// is declared static.
    ///
212
213
    /// @todo: This should be named static Pkt4::getName()
    ///
214
215
216
217
218
219
220
    /// @param type DHCPv4 packet type
    ///
    /// @return Pointer to "const" string containing the packet name.
    ///         Note that this string is statically allocated and MUST NOT
    ///         be freed by the caller.
    static const char* serverReceivedPacketName(uint8_t type);

221
222
223
224
225
226
227
    ///
    /// @name Public accessors returning values required to (re)open sockets.
    ///
    //@{
    ///
    /// @brief Get UDP port on which server should listen.
    ///
228
229
230
    /// Typically, server listens on UDP port number 67. Other ports are used
    /// for testing purposes only.
    ///
231
232
233
234
235
236
237
238
239
240
241
242
243
244
    /// @return UDP port on which server should listen.
    uint16_t getPort() const {
        return (port_);
    }

    /// @brief Return bool value indicating that broadcast flags should be set
    /// on sockets.
    ///
    /// @return A bool value indicating that broadcast should be used (if true).
    bool useBroadcast() const {
        return (use_bcast_);
    }
    //@}

245
246
247
248
249
250
251
252
253
    /// @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
    /// D2ClientErrors. This method does not catch exceptions.
    void startD2();

    /// @brief Implements the error handler for DHCP_DDNS IO errors
    ///
254
    /// Invoked when a NameChangeRequest send to kea-dhcp-ddns completes with
255
256
257
258
259
260
261
262
263
264
265
266
267
268
    /// 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);
269
protected:
270

271
272
273
274
275
276
277
    /// @name Functions filtering and sanity-checking received messages.
    ///
    /// @todo These functions are supposed to be moved to a new class which
    /// will manage different rules for accepting and rejecting messages.
    /// Perhaps ticket #3116 is a good opportunity to do it.
    ///
    //@{
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
    /// @brief Checks whether received message should be processed or discarded.
    ///
    /// This function checks whether received message should be processed or
    /// discarded. It should be called on the beginning of message processing
    /// (just after the message has been decoded). This message calls a number
    /// of other functions which check whether message should be processed,
    /// using different criteria.
    ///
    /// This function should be extended when new criteria for accepting
    /// received message have to be implemented. This function is meant to
    /// aggregate all early filtering checks on the received message. By having
    /// a single function like this, we are avoiding bloat of the server's main
    /// loop.
    ///
    /// @warning This function should remain exception safe.
    ///
    /// @param query Received message.
    ///
    /// @return true if the message should be further processed, or false if
    /// the message should be discarded.
    bool accept(const Pkt4Ptr& query) const;

    /// @brief Check if a message sent by directly connected client should be
Francis Dupont's avatar
Francis Dupont committed
301
    /// accepted or discarded.
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
    ///
    /// This function checks if the received message is from directly connected
    /// client. If it is, it checks that it should be processed or discarded.
    ///
    /// Note that this function doesn't validate all addresses being carried in
    /// the message. The primary purpose of this function is to filter out
    /// direct messages in the local network for which there is no suitable
    /// subnet configured. For example, this function accepts unicast messages
    /// because unicasts may be used by clients located in remote networks to
    /// to renew existing leases. If their notion of address is wrong, the
    /// server will have to sent a NAK, instead of dropping the message.
    /// Detailed validation of such messages is performed at later stage of
    /// processing.
    ///
    /// This function accepts the following messages:
    /// - all valid relayed messages,
    /// - all unicast messages,
319
320
321
    /// - all broadcast messages except DHCPINFORM received on the interface
    /// for which the suitable subnet exists (is configured).
    /// - all DHCPINFORM messages with source address or ciaddr set.
322
    ///
323
    /// @param query Message sent by a client.
324
325
326
    ///
    /// @return true if message is accepted for further processing, false
    /// otherwise.
327
328
329
330
331
    bool acceptDirectRequest(const Pkt4Ptr& query) const;

    /// @brief Check if received message type is valid for the server to
    /// process.
    ///
Francis Dupont's avatar
Francis Dupont committed
332
333
334
    /// This function checks that the received message type belongs to
    /// the range of types recognized by the server and that the
    /// message of this type should be processed by the server.
335
336
337
338
339
340
341
342
343
344
345
346
347
    ///
    /// The messages types accepted for processing are:
    /// - Discover
    /// - Request
    /// - Release
    /// - Decline
    /// - Inform
    ///
    /// @param query Message sent by a client.
    ///
    /// @return true if message is accepted for further processing, false
    /// otherwise.
    bool acceptMessageType(const Pkt4Ptr& query) const;
348

349
350
351
352
353
354
355
356
357
358
359
360
361
362
    /// @brief Verifies if the server id belongs to our server.
    ///
    /// This function checks if the server identifier carried in the specified
    /// DHCPv4 message belongs to this server. If the server identifier option
    /// is absent or the value carried by this option is equal to one of the
    /// server identifiers used by the server, the true is returned. If the
    /// server identifier option is present, but it doesn't match any server
    /// identifier used by this server, the false value is returned.
    ///
    /// @param pkt DHCPv4 message which server identifier is to be checked.
    ///
    /// @return true, if the server identifier is absent or matches one of the
    /// server identifiers that the server is using; false otherwise.
    bool acceptServerId(const Pkt4Ptr& pkt) const;
363
    //@}
364

365
    /// @brief Verifies if specified packet meets RFC requirements
366
367
368
369
    ///
    /// Checks if mandatory option is really there, that forbidden option
    /// is not there, and that client-id or server-id appears only once.
    ///
370
    /// @param query Pointer to the client's message.
371
372
    /// @param serverid expectation regarding server-id option
    /// @throw RFCViolation if any issues are detected
373
    static void sanityCheck(const Pkt4Ptr& query, RequirementLevel serverid);
374

375
376
377
378
379
380
    /// @brief Processes incoming DISCOVER and returns response.
    ///
    /// Processes received DISCOVER message and verifies that its sender
    /// should be served. In particular, a lease is selected and sent
    /// as an offer to a client if it should be served.
    ///
381
    /// @param discover DISCOVER message received from client
382
383
    ///
    /// @return OFFER message or NULL
384
    Pkt4Ptr processDiscover(Pkt4Ptr& discover);
385
386
387
388
389

    /// @brief Processes incoming REQUEST and returns REPLY response.
    ///
    /// Processes incoming REQUEST message and verifies that its sender
    /// should be served. In particular, verifies that requested lease
Tomek Mrugalski's avatar
Tomek Mrugalski committed
390
    /// is valid, not expired, not reserved, not used by other client and
391
392
    /// that requesting client is allowed to use it.
    ///
393
    /// Returns ACK message, NAK message, or NULL
394
395
396
    ///
    /// @param request a message received from client
    ///
397
    /// @return ACK or NAK message
398
    Pkt4Ptr processRequest(Pkt4Ptr& request);
399
400
401
402
403
404
405

    /// @brief Stub function that will handle incoming RELEASE messages.
    ///
    /// In DHCPv4, server does not respond to RELEASE messages, therefore
    /// this function does not return anything.
    ///
    /// @param release message received from client
406
    void processRelease(Pkt4Ptr& release);
407
408
409
410

    /// @brief Stub function that will handle incoming DHCPDECLINE messages.
    ///
    /// @param decline message received from client
411
    void processDecline(Pkt4Ptr& decline);
412
413
414

    /// @brief Stub function that will handle incoming INFORM messages.
    ///
415
    /// @param inform message received from client
416
    Pkt4Ptr processInform(Pkt4Ptr& inform);
417

Tomek Mrugalski's avatar
Tomek Mrugalski committed
418
419
420
    /// @brief Appends options requested by client.
    ///
    /// This method assigns options that were requested by client
Tomek Mrugalski's avatar
Tomek Mrugalski committed
421
    /// (sent in PRL) or are enforced by server.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
422
    ///
423
424
    /// @param ex The exchange holding both the client's message and the
    /// server's response.
425
    void appendRequestedOptions(Dhcpv4Exchange& ex);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
426

427
428
429
430
431
432
433
434
    /// @brief Appends requested vendor options as requested by client.
    ///
    /// This method is similar to \ref appendRequestedOptions(), but uses
    /// vendor options. The major difference is that vendor-options use
    /// its own option spaces (there may be more than one distinct set of vendor
    /// options, each with unique vendor-id). Vendor options are requested
    /// using separate options within their respective vendor-option spaces.
    ///
435
436
    /// @param ex The exchange holding both the client's message and the
    /// server's response.
437
    void appendRequestedVendorOptions(Dhcpv4Exchange& ex);
438

Tomek Mrugalski's avatar
Tomek Mrugalski committed
439
440
    /// @brief Assigns a lease and appends corresponding options
    ///
Francis Dupont's avatar
Francis Dupont committed
441
    /// This method chooses the most appropriate lease for requesting
Tomek Mrugalski's avatar
Tomek Mrugalski committed
442
443
444
    /// client and assigning it. Options corresponding to the lease
    /// are added to specific message.
    ///
445
446
447
448
449
450
451
452
    /// This method may reset the pointer to the response in the @c ex object
    /// to indicate that the response should not be sent to the client.
    /// The caller must check if the response is is null after calling
    /// this method.
    ///
    /// The response type in the @c ex object may be set to DHCPACK or DHCPNAK.
    ///
    /// @param ex DHCPv4 exchange holding the client's message to be checked.
453
    void assignLease(Dhcpv4Exchange& ex);
454

455
456
457
    /// @brief Append basic options if they are not present.
    ///
    /// This function adds the following basic options if they
458
    /// are not yet added to the response message:
459
460
461
462
463
    /// - Subnet Mask,
    /// - Router,
    /// - Name Server,
    /// - Domain Name.
    ///
464
    /// @param ex DHCPv4 exchange holding the client's message to be checked.
465
    void appendBasicOptions(Dhcpv4Exchange& ex);
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
    /// @brief Processes Client FQDN and Hostname Options sent by a client.
    ///
    /// Client may send Client FQDN or Hostname option to communicate its name
    /// to the server. Server may use this name to perform DNS update for the
    /// lease being assigned to a client. If server takes responsibility for
    /// updating DNS for a client it may communicate it by sending the Client
    /// FQDN or Hostname %Option back to the client. Server select a different
    /// name than requested by a client to update DNS. In such case, the server
    /// stores this different name in its response.
    ///
    /// Client should not send both Client FQDN and Hostname options. However,
    /// if client sends both options, server should prefer Client FQDN option
    /// and ignore the Hostname option. If Client FQDN option is not present,
    /// the Hostname option is processed.
    ///
    /// The Client FQDN %Option is processed by this function as described in
    /// RFC4702.
    ///
    /// In response to a Hostname %Option sent by a client, the server may send
    /// Hostname option with the same or different hostname. If different
    /// hostname is sent, it is an indication to the client that server has
    /// overridden the client's preferred name and will rather use this
    /// different name to update DNS. However, since Hostname option doesn't
    /// carry an information whether DNS update will be carried by the server
    /// or not, the client is responsible for checking whether DNS update
    /// has been performed.
    ///
    /// After successful processing options stored in the first parameter,
    /// this function may add Client FQDN or Hostname option to the response
    /// message. In some cases, server may cease to add any options to the
    /// response, i.e. when server doesn't support DNS updates.
    ///
499
500
501
    /// This function does not throw. It simply logs the debug message if the
    /// processing of the FQDN or Hostname failed.
    ///
502
503
    /// @param ex The exchange holding both the client's message and the
    /// server's response.
504
    void processClientName(Dhcpv4Exchange& ex);
505

506
507
508
509
510
511
512
513
    /// @brief this is a prefix added to the contend 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;

514
515
516
private:
    /// @brief Process Client FQDN %Option sent by a client.
    ///
517
518
519
520
521
522
    /// This function is called by the @c Dhcpv4Srv::processClientName when
    /// the client has sent the FQDN option in its message to the server.
    /// It comprises the actual logic to parse the FQDN option and prepare
    /// the FQDN option to be sent back to the client in the server's
    /// response.
    ///
523
524
    /// @param ex The exchange holding both the client's message and the
    /// server's response.
525
    void processClientFqdnOption(Dhcpv4Exchange& ex);
526
527
528

    /// @brief Process Hostname %Option sent by a client.
    ///
Francis Dupont's avatar
Francis Dupont committed
529
    /// This function is called by the @c Dhcpv4Srv::processClientName when
530
531
532
533
534
    /// the client has sent the Hostname option in its message to the server.
    /// It comprises the actual logic to parse the Hostname option and
    /// prepare the Hostname option to be sent back to the client in the
    /// server's response.
    ///
535
536
    /// @param ex The exchange holding both the client's message and the
    /// server's response.
537
    void processHostnameOption(Dhcpv4Exchange& ex);
538
539

protected:
540
541
542
543

    /// @brief Creates NameChangeRequests which correspond to the lease
    /// which has been acquired.
    ///
Francis Dupont's avatar
Francis Dupont committed
544
    /// If this function is called when an existing lease is renewed, it
545
546
547
548
549
550
551
552
553
554
555
556
557
    /// may generate NameChangeRequest to remove existing DNS entries which
    /// correspond to the old lease instance. This function may cease to
    /// generate NameChangeRequests if the notion of the client's FQDN hasn't
    /// changed between an old and new lease.
    ///
    /// @param lease A pointer to the new lease which has been acquired.
    /// @param old_lease A pointer to the instance of the old lease which has
    /// been replaced by the new lease passed in the first argument. The NULL
    /// value indicates that the new lease has been allocated, rather than
    /// lease being renewed.
    void createNameChangeRequests(const Lease4Ptr& lease,
                                  const Lease4Ptr& old_lease);

558
559
    /// @brief Creates the NameChangeRequest and adds to the queue for
    /// processing.
560
    ///
561
562
563
    /// This creates the @c isc::dhcp_ddns::NameChangeRequest; emits a
    /// the debug message which indicates whether the request being added is
    /// to remove DNS entry or add a new entry; and then sends the request
564
    /// to the D2ClientMgr for transmission to kea-dhcp-ddns.
565
    ///
566
    /// @param chg_type A type of the NameChangeRequest (ADD or REMOVE).
567
568
    /// @param lease A lease for which the NameChangeRequest is created and
    /// queued.
569
570
    void queueNameChangeRequest(const isc::dhcp_ddns::NameChangeType chg_type,
                                const Lease4Ptr& lease);
571

572
573
574
575
576
    /// @brief Attempts to renew received addresses
    ///
    /// Attempts to renew existing lease. This typically includes finding a lease that
    /// corresponds to the received address. If no such lease is found, a status code
    /// response is generated.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
577
    ///
578
579
580
    /// @param renew client's message asking for renew
    /// @param reply server's response (ACK or NAK)
    void renewLease(const Pkt4Ptr& renew, Pkt4Ptr& reply);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
581

582
583
    /// @brief Adds server identifier option to the server's response.
    ///
Francis Dupont's avatar
Francis Dupont committed
584
    /// This method adds a server identifier to the DHCPv4 message. It expects
585
586
587
588
589
590
591
592
593
594
595
    /// that the local (source) address is set for this message. If address is
    /// not set, it will throw an exception. This method also expects that the
    /// server identifier option is not present in the specified message.
    /// Otherwise, it will throw an exception on attempt to add a duplicate
    /// server identifier option.
    ///
    /// @note This method doesn't throw exceptions by itself but the underlying
    /// classes being used my throw. The reason for this method to not sanity
    /// check the specified message is that it is meant to be called internally
    /// by the @c Dhcpv4Srv class.
    ///
596
597
598
    /// @note This method is static because it is not dependent on the class
    /// state.
    ///
599
600
    /// @param ex The exchange holding both the client's message and the
    /// server's response.
601
    static void appendServerID(Dhcpv4Exchange& ex);
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618

    /// @brief Set IP/UDP and interface parameters for the DHCPv4 response.
    ///
    /// This method sets the following parameters for the DHCPv4 message being
    /// sent to a client:
    /// - client unicast or a broadcast address,
    /// - client or relay port,
    /// - server address,
    /// - server port,
    /// - name and index of the interface which is to be used to send the
    /// message.
    ///
    /// Internally it calls the @c Dhcpv4Srv::adjustRemoteAddr to figure
    /// out the destination address (client unicast address or broadcast
    /// address).
    ///
    /// The destination port is always DHCPv4 client (68) or relay (67) port,
619
    /// depending if the response will be sent directly to a client.
620
621
622
623
624
625
626
627
628
629
    ///
    /// The source port is always set to DHCPv4 server port (67).
    ///
    /// The interface selected for the response is always the same as the
    /// one through which the query has been received.
    ///
    /// The source address for the response is the IPv4 address assigned to
    /// the interface being used to send the response. This function uses
    /// @c IfaceMgr to get the socket bound to the IPv4 address on the
    /// particular interface.
630
631
632
    ///
    /// @note This method is static because it is not dependent on the class
    /// state.
633
634
635
    ///
    /// @param ex The exchange holding both the client's message and the
    /// server's response.
636
    static void adjustIfaceData(Dhcpv4Exchange& ex);
637

638
639
640
641
642
643
644
645
646
647
648
649
650
    /// @brief Sets remote addresses for outgoing packet.
    ///
    /// This method sets the local and remote addresses on outgoing packet.
    /// The addresses being set depend on the following conditions:
    /// - has incoming packet been relayed,
    /// - is direct response to a client without address supported,
    /// - type of the outgoing packet,
    /// - broadcast flag set in the incoming packet.
    ///
    /// @warning This method does not check whether provided packet pointers
    /// are valid. Make sure that pointers are correct before calling this
    /// function.
    ///
651
652
653
    /// @note This method is static because it is not dependent on the class
    /// state.
    ///
654
655
    /// @param ex The exchange holding both the client's message and the
    /// server's response.
656
    static void adjustRemoteAddr(Dhcpv4Exchange& ex);
657

658
659
660
661
662
663
664
    /// @brief converts server-id to text
    /// Converts content of server-id option to a text representation, e.g.
    /// "192.0.2.1"
    ///
    /// @param opt option that contains server-id
    /// @return string representation
    static std::string srvidToString(const OptionPtr& opt);
665

666
    /// @brief Computes DHCID from a lease.
667
    ///
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
    /// This method creates an object which represents DHCID. The DHCID value
    /// is computed as described in RFC4701. The section 3.3. of RFC4701
    /// specifies the DHCID RR Identifier Type codes:
    /// - 0x0000 The 1 octet htype followed by glen octets of chaddr
    /// - 0x0001 The data octets from the DHCPv4 client's Client Identifier
    /// option.
    /// - 0x0002 The client's DUID.
    ///
    /// Currently this function supports first two of these identifiers.
    /// The 0x0001 is preferred over the 0x0000 - if the client identifier
    /// option is present, the former is used. If the client identifier
    /// is absent, the latter is used.
    ///
    /// @todo Implement support for 0x0002 DHCID identifier type.
    ///
683
    /// @param lease A pointer to the structure describing a lease.
684
    /// @return An object encapsulating DHCID to be used for DNS updates.
685
    /// @throw DhcidComputeError If the computation of the DHCID failed.
686
    static isc::dhcp_ddns::D2Dhcid computeDhcid(const Lease4Ptr& lease);
687

688
689
    /// @brief Selects a subnet for a given client's packet.
    ///
690
    /// @param query client's message
691
    /// @return selected subnet (or NULL if no suitable subnet was found)
692
    isc::dhcp::Subnet4Ptr selectSubnet(const Pkt4Ptr& query) const;
693

694
695
    /// indicates if shutdown is in progress. Setting it to true will
    /// initiate server shutdown procedure.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
696
    volatile bool shutdown_;
697

698
699
700
701
702
703
704
705
706
707
708
709
    /// @brief dummy wrapper around IfaceMgr::receive4
    ///
    /// This method is useful for testing purposes, where its replacement
    /// simulates reception of a packet. For that purpose it is protected.
    virtual Pkt4Ptr 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 Pkt4Ptr& pkt);

710
711
712
713
714
715
716
717
718
719
720
721
    /// @brief Implements a callback function to parse options in the message.
    ///
    /// @param buf a A buffer holding options in on-wire format.
    /// @param option_space A name of the option space which holds definitions
    /// of to be used to parse options in the packets.
    /// @param [out] options A reference to the collection where parsed options
    /// will be stored.
    /// @return An offset to the first byte after last parsed option.
    size_t unpackOptions(const OptionBuffer& buf,
                         const std::string& option_space,
                         isc::dhcp::OptionCollection& options);

722
723
724
725
726
727
728
    /// @brief Assigns incoming packet to zero or more classes.
    ///
    /// @note For now, the client classification is very simple. It just uses
    /// content of the vendor-class-identifier option as a class. The resulting
    /// class will be stored in packet (see @ref isc::dhcp::Pkt4::classes_ and
    /// @ref isc::dhcp::Pkt4::inClass).
    ///
729
730
731
732
733
    /// @param pkt packet to be classified
    void classifyPacket(const Pkt4Ptr& pkt);

    /// @brief Performs packet processing specific to a class
    ///
734
735
    /// If the selected subnet, query or response in the @c ex object is NULL
    /// this method returns immediately and returns true.
736
    ///
737
738
739
740
    /// @note This processing is a likely candidate to be pushed into hooks.
    ///
    /// @param ex The exchange holding both the client's message and the
    /// server's response.
741
    /// @return true if successful, false otherwise (will prevent sending response)
742
    bool classSpecificProcessing(const Dhcpv4Exchange& ex);
743

744
745
746
747
748
749
    /// @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_;

750
private:
751
752

    /// @brief Constructs netmask option based on subnet4
753
    /// @param subnet subnet for which the netmask will be calculated
754
755
756
757
    ///
    /// @return Option that contains netmask information
    static OptionPtr getNetmaskOption(const Subnet4Ptr& subnet);

758
759
760
761
762
763
764
765
766
    /// @brief Implements the error handler for socket open failure.
    ///
    /// This callback function is installed on the @c isc::dhcp::IfaceMgr
    /// when IPv4 sockets are being open. When socket fails to open for
    /// any reason, this function is called. It simply logs the error message.
    ///
    /// @param errmsg An error message containing a cause of the failure.
    static void ifaceMgrSocket4ErrorHandler(const std::string& errmsg);

767
768
769
    uint16_t port_;  ///< UDP port number on which server listens.
    bool use_bcast_; ///< Should broadcast be enabled on sockets (if true).

770
771
772
773
    /// Indexes for registered hook points
    int hook_index_pkt4_receive_;
    int hook_index_subnet4_select_;
    int hook_index_pkt4_send_;
774
775
776
777
778
779
};

}; // namespace isc::dhcp
}; // namespace isc

#endif // DHCP4_SRV_H