dhcp4_srv.h 16.7 KB
Newer Older
1
// Copyright (C) 2011-2013 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
22
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/alloc_engine.h>
23
#include <hooks/callout_handle.h>
24
25
26

#include <boost/noncopyable.hpp>

27
28
29
30
#include <iostream>

namespace isc {
namespace dhcp {
31

32
33
34
35
36
37
38
39
/// @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.
40
41
///
/// This class does not support any controlling mechanisms directly.
42
/// See the derived \ref ControlledDhcpv4Srv class for support for
43
44
45
46
/// command and configuration updates over msgq.
///
/// For detailed explanation or relations between main(), ControlledDhcpv4Srv,
/// Dhcpv4Srv and other classes, see \ref dhcpv4Session.
47
48
class Dhcpv4Srv : public boost::noncopyable {

49
public:
50
51
52
53
54
55
56
57

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

58
59
    /// @brief Default constructor.
    ///
60
    /// Instantiates necessary services, required to run DHCPv4 server.
61
62
    /// In particular, creates IfaceMgr that will be responsible for
    /// network interaction. Will instantiate lease manager, and load
Tomek Mrugalski's avatar
Tomek Mrugalski committed
63
64
    /// old or create new DUID. It is possible to specify alternate
    /// port on which DHCPv4 server will listen on. That is mostly useful
65
66
    /// 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
67
68
69
    /// 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
70
71
    ///
    /// @param port specifies port number to listen on
72
73
    /// @param dbconfig Lease manager configuration string.  The default
    ///        of the "memfile" manager is used for testing.
74
    /// @param use_bcast configure sockets to support broadcast messages.
75
76
    /// @param direct_response_desired specifies if it is desired to
    /// use direct V4 traffic.
77
    Dhcpv4Srv(uint16_t port = DHCP4_SERVER_PORT,
78
              const char* dbconfig = "type=memfile",
79
80
              const bool use_bcast = true,
              const bool direct_response_desired = true);
81

82
    /// @brief Destructor. Used during DHCPv4 service shutdown.
83
    virtual ~Dhcpv4Srv();
84
85
86
87
88
89
90
91
92
93
94

    /// @brief Main server processing loop.
    ///
    /// Main server processing loop. Receives incoming packets, verifies
    /// their correctness, generates appropriate answer (if needed) and
    /// transmits respones.
    ///
    /// @return true, if being shut down gracefully, fail if experienced
    ///         critical error.
    bool run();

95
    /// @brief Instructs the server to shut down.
96
97
    void shutdown();

98
99
100
101
102
    /// @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
103
    /// "UNKNOWN" is returned.  This method is used in debug messages.
104
105
106
107
    ///
    /// As the operation of the method does not depend on any server state, it
    /// is declared static.
    ///
108
109
    /// @todo: This should be named static Pkt4::getName()
    ///
110
111
112
113
114
115
116
    /// @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);

117
118
119
120
121
122
123
124
125
126
127
128
    ///
    /// @name Public accessors returning values required to (re)open sockets.
    ///
    /// These accessors must be public because sockets are reopened from the
    /// static configuration callback handler. This callback handler invokes
    /// @c ControlledDhcpv4Srv::openActiveSockets which requires parameters
    /// which has to be retrieved from the @c ControlledDhcpv4Srv object.
    /// They are retrieved using these public functions
    //@{
    ///
    /// @brief Get UDP port on which server should listen.
    ///
129
130
131
    /// Typically, server listens on UDP port number 67. Other ports are used
    /// for testing purposes only.
    ///
132
133
134
135
136
137
138
139
140
141
142
143
144
145
    /// @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_);
    }
    //@}

146
147
148
149
150
151
152
153
154
155
156
    /// @brief Open sockets which are marked as active in @c CfgMgr.
    ///
    /// This function reopens sockets according to the current settings in the
    /// Configuration Manager. It holds the list of the interfaces which server
    /// should listen on. This function will open sockets on these interfaces
    /// only. This function is not exception safe.
    ///
    /// @param port UDP port on which server should listen.
    /// @param use_bcast should broadcast flags be set on the sockets.
    static void openActiveSockets(const uint16_t port, const bool use_bcast);

157
protected:
158
159
160
161
162
163
164
165
166
167
168

    /// @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 serverid expectation regarding server-id option
    /// @throw RFCViolation if any issues are detected
    void sanityCheck(const Pkt4Ptr& pkt, RequirementLevel serverid);

169
170
171
172
173
174
    /// @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.
    ///
175
    /// @param discover DISCOVER message received from client
176
177
    ///
    /// @return OFFER message or NULL
178
    Pkt4Ptr processDiscover(Pkt4Ptr& discover);
179
180
181
182
183

    /// @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
184
    /// is valid, not expired, not reserved, not used by other client and
185
186
    /// that requesting client is allowed to use it.
    ///
187
    /// Returns ACK message, NAK message, or NULL
188
189
190
    ///
    /// @param request a message received from client
    ///
191
    /// @return ACK or NAK message
192
    Pkt4Ptr processRequest(Pkt4Ptr& request);
193
194
195
196
197
198
199

    /// @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
200
    void processRelease(Pkt4Ptr& release);
201
202
203
204

    /// @brief Stub function that will handle incoming DHCPDECLINE messages.
    ///
    /// @param decline message received from client
205
    void processDecline(Pkt4Ptr& decline);
206
207
208

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

212
213
214
215
216
217
218
    /// @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.
    ///
    /// @param question any message sent by client
    /// @param answer any message server is going to send as response
219
    void copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
220
221
222
223

    /// @brief Appends options requested by client.
    ///
    /// This method assigns options that were requested by client
Tomek Mrugalski's avatar
Tomek Mrugalski committed
224
    /// (sent in PRL) or are enforced by server.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
225
    ///
226
    /// @param question DISCOVER or REQUEST message from a client.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
227
    /// @param msg outgoing message (options will be added here)
228
    void appendRequestedOptions(const Pkt4Ptr& question, Pkt4Ptr& msg);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
229

230
231
232
233
234
235
236
237
238
239
240
241
    /// @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.
    ///
    /// @param question DISCOVER or REQUEST message from a client.
    /// @param msg outgoing message (options will be added here)
    void appendRequestedVendorOptions(const Pkt4Ptr& question, Pkt4Ptr& answer);

Tomek Mrugalski's avatar
Tomek Mrugalski committed
242
243
244
245
246
247
    /// @brief Assigns a lease and appends corresponding options
    ///
    /// This method chooses the most appropriate lease for reqesting
    /// client and assigning it. Options corresponding to the lease
    /// are added to specific message.
    ///
248
249
250
251
    /// @param question DISCOVER or REQUEST message from client
    /// @param answer OFFER or ACK/NAK message (lease options will be added here)
    void assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer);

252
253
254
255
256
257
258
259
260
261
262
263
264
    /// @brief Append basic options if they are not present.
    ///
    /// This function adds the following basic options if they
    /// are not yet added to the message:
    /// - Subnet Mask,
    /// - Router,
    /// - Name Server,
    /// - Domain Name.
    ///
    /// @param question DISCOVER or REQUEST message from a client.
    /// @param msg the message to add options to.
    void appendBasicOptions(const Pkt4Ptr& question, Pkt4Ptr& msg);

265
266
267
268
269
    /// @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
270
    ///
271
272
273
    /// @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
274

275
276
277
278
    /// @brief Appends default options to a message
    ///
    /// @param msg message object (options will be added to it)
    /// @param msg_type specifies message type
279
    void appendDefaultOptions(Pkt4Ptr& msg, uint8_t msg_type);
280

281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
    /// @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.
    ///
    /// @param question instance of a packet received by a server.
    /// @param [out] msg response packet which addresses are to be adjusted.
    void adjustRemoteAddr(const Pkt4Ptr& question, Pkt4Ptr& msg);

298
    /// @brief Returns server-identifier option
299
300
    ///
    /// @return server-id option
301
    OptionPtr getServerID() { return serverid_; }
302
303
304
305
306
307
308
309
310
311

    /// @brief Sets server-identifier.
    ///
    /// This method attempts to set server-identifier DUID. It tries to
    /// load previously stored IP from configuration. If there is no previously
    /// stored server identifier, it will pick up one address from configured
    /// and supported network interfaces.
    ///
    /// @throws isc::Unexpected Failed to obtain server identifier (i.e. no
    //          previously stored configuration and no network interfaces available)
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
    void generateServerID();

    /// @brief attempts to load server-id from a file
    ///
    /// Tries to load duid from a text file. If the load is successful,
    /// it creates server-id option and stores it in serverid_ (to be used
    /// later by getServerID()).
    ///
    /// @param file_name name of the server-id file to load
    /// @return true if load was successful, false otherwise
    bool loadServerID(const std::string& file_name);

    /// @brief attempts to write server-id to a file
    /// Tries to write server-id content (stored in serverid_) to a text file.
    ///
    /// @param file_name name of the server-id file to write
    /// @return true if write was successful, false otherwise
    bool writeServerID(const std::string& file_name);

    /// @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);
338

339
340
341
342
343
344
    /// @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::Subnet4Ptr selectSubnet(const Pkt4Ptr& question);

345
    /// server DUID (to be sent in server-identifier option)
346
    OptionPtr serverid_;
347
348
349

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

352
353
354
355
356
357
358
359
360
361
362
363
    /// @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);

364
365
366
367
368
369
370
371
372
373
374
375
    /// @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);

376
377
private:

378
    /// @brief Constructs netmask option based on subnet4
379
    /// @param subnet subnet for which the netmask will be calculated
380
381
382
383
    ///
    /// @return Option that contains netmask information
    static OptionPtr getNetmaskOption(const Subnet4Ptr& subnet);

384
385
386
387
388
389
390
391
392
    /// @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);

393
394
395
396
397
398
    /// @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_;

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

402
403
404
405
    /// Indexes for registered hook points
    int hook_index_pkt4_receive_;
    int hook_index_subnet4_select_;
    int hook_index_pkt4_send_;
406
407
408
409
410
411
};

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

#endif // DHCP4_SRV_H