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

#ifndef HOST_H
#define HOST_H

#include <asiolink/io_address.h>
#include <dhcp/classify.h>
#include <dhcp/duid.h>
#include <dhcp/hwaddr.h>
14
#include <dhcpsrv/cfg_option.h>
15
#include <dhcpsrv/subnet_id.h>
16
#include <boost/shared_ptr.hpp>
17 18 19 20 21 22 23 24
#include <list>
#include <map>
#include <string>
#include <utility>

namespace isc {
namespace dhcp {

Tomek Mrugalski's avatar
Tomek Mrugalski committed
25 26 27
/// @brief HostID (used only when storing in MySQL or Postgres)
typedef uint64_t HostID;

28 29
/// @brief IPv6 reservation for a host.
///
30 31 32 33 34 35
/// This class represents a reservation for a host of a single IPv6
/// address or prefix (in @c Host object).
///
/// The class holds the address and prefix length, a value of 128
/// for the latter implying that the reservation is for a single
/// IPv6 address.
36 37 38
class IPv6Resrv {
public:

39 40 41
    /// @brief Type of the reservation.
    ///
    /// Currently supported types are NA and PD.
42 43 44 45 46
    enum Type {
        TYPE_NA,
        TYPE_PD
    };

47 48 49 50 51 52 53
    /// @brief Constructor.
    ///
    /// Creates a reservation from the IPv6 address and prefix length
    /// value. If the prefix length is not specified, the default value
    /// of 128 is used. This value indicates that the reservation is made
    /// for an IPv6 address.
    ///
54
    /// @param type Reservation type: NA or PD.
55 56
    /// @param prefix Address or prefix to be reserved.
    /// @param prefix_len Prefix length.
57
    ///
58 59
    /// @throw isc::BadValue if prefix is not IPv6 prefix, is a
    /// multicast address or the prefix length is greater than 128.
60 61
    IPv6Resrv(const Type& type,
              const asiolink::IOAddress& prefix,
62
              const uint8_t prefix_len = 128);
63

64 65 66
    /// @brief Returns prefix for the reservation.
    const asiolink::IOAddress& getPrefix() const {
        return (prefix_);
67 68
    }

69
    /// @brief Returns prefix length.
70 71 72 73
    uint8_t getPrefixLen() const {
        return (prefix_len_);
    }

74 75 76 77 78
    /// @brief Returns reservation type.
    ///
    /// The type of reservation is determined using a prefix length.
    ///
    /// @return NA for prefix length equal to 128, PD otherwise.
79
    Type getType() const {
80
        return (type_);
81 82
    }

83 84
    /// @brief Sets a new prefix and prefix length.
    ///
85
    /// @param type Reservation type: NA or PD.
86 87
    /// @param prefix New prefix.
    /// @param prefix_len New prefix length.
88 89 90
    ///
    /// @throw isc::BadValue if prefix is not IPv6 prefix, is a
    /// multicast address or the prefix length is greater than 128.
91 92
    void set(const Type& type, const asiolink::IOAddress& prefix,
             const uint8_t prefix_len);
93

94 95 96
    /// @brief Returns information about the reservation in the textual format.
    std::string toText() const;

97 98 99 100 101 102 103 104 105 106
    /// @brief Equality operator.
    ///
    /// @param other Reservation to compare to.
    bool operator==(const IPv6Resrv& other) const;

    /// @brief Inequality operator.
    ///
    /// @param other Reservation to compare to.
    bool operator!=(const IPv6Resrv& other) const;

107
private:
108 109

    Type type_;                  ///< Reservation type.
110 111
    asiolink::IOAddress prefix_; ///< Prefix
    uint8_t prefix_len_;         ///< Prefix length.
112 113 114 115 116

};

/// @brief Collection of IPv6 reservations for the host.
typedef std::multimap<IPv6Resrv::Type, IPv6Resrv> IPv6ResrvCollection;
117 118
typedef IPv6ResrvCollection::const_iterator IPv6ResrvIterator;
typedef std::pair<IPv6Resrv::Type, IPv6Resrv> IPv6ResrvTuple;
119 120
typedef std::pair<IPv6ResrvIterator, IPv6ResrvIterator> IPv6ResrvRange;

121 122
/// @brief Represents a device with IPv4 and/or IPv6 reservations.
///
123
/// This class represents a network device which can be identified
124
/// by a unique property, such as MAC address on the interface or
125 126 127 128 129 130 131 132 133 134 135 136
/// client identifier (DUID), and for which some resources are statically
/// assigned:
/// - IPv4 address which the device obtains when it contacts a DHCPv4 server
/// - IPv6 address(es) which the device obtains when it contacts a DHCPv6
/// server
/// - IPv6 prefix(es) obtained when the device contacts the DHCPv6 server
/// and requests allocation of prefixes using prefix delegation mechanism
/// - hostname which is used for dynamic DNS updates for both DHCPv4 and
/// DHCPv6 exchanges.
/// - client classes which the client is associated with
/// - DHCP options specifically configured for the device
///
137
/// Note, that "host" in this context has a different meaning from
138 139 140 141
/// host construed as device attached to a network with (possibly) multiple
/// interfaces. For the MAC address based reservations, each interface on a
/// network device maps to a single @c Host object as each @c Host object
/// contains at most one MAC address. So, it is possible that a single
142 143 144 145
/// device is associated with multiple distinct @c Host objects if the
/// device has multiple interfaces. Under normal circumstances, a non-mobile
/// dual stack device using one interface should be represented by a single
/// @c Host object.
146 147 148 149 150 151 152 153 154
///
/// A DHCPv6 DUID is common for all interfaces on a device. Therefore, for
/// DUID based reservations a @c Host object may represent a network device with
/// multiple interfaces. However, since @c Host objects are grouped by
/// subnets to which device's interfaces are connected a single instance of
/// @c Host object usually defines reservations for a single interface.
///
/// The @c Host object combines reservations for both IPv4 and IPv6 resources
/// to allow for correlation of the information about the dual stack devices
155 156 157
/// using DHCPv4 and DHCPv6 respectively. For example: both the DHCPv4 and
/// DHCPv6 servers may use the same database for storing host reservations, so
/// the information about the DHCPv4 reservations are available for the
158 159
/// DHCPv6 server and vice versa. Also, this approach allows for reserving
/// common resources such as host name for DHCPv4 and DHCPv6 clients.
160
///
161 162 163 164 165
/// This class also holds pointers to specific DHCP options reserved
/// for a host. Options instances are held in @c CfgOption objects.
/// There are two @c CfgOption objects in this class, one holding
/// DHCPv4 options, another one holding DHCPv6 options.
///
166 167 168 169 170 171 172
/// @todo This class offers basic functionality for storing host information.
/// It will need to be extended to allow for the following operations:
/// - remove and replace IPv6 reservations
/// - remove and replace client classes
/// - disable IPv4 reservation without a need to set it to the 0.0.0.0 address
/// Note that the last three operations are mainly required for managing
/// host reservations which will be implemented later.
173 174 175
class Host {
public:

176 177 178 179
    /// @brief Type of the host identifier.
    ///
    /// Currently hardware address assigned to an interface and the
    /// DHCPv6 client's DUID are supported.
180 181
    enum IdentifierType {
        IDENT_HWADDR,
182 183
        IDENT_DUID,
        IDENT_CIRCUIT_ID
184 185
    };

186 187
    /// @brief Constructor.
    ///
188 189
    /// Creates a @c Host object using an identifier in a binary format. This
    /// is most useful in cases where the identifier is obtained from the
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
    /// database. The constructor will create an instance of the @c HWAddr
    /// or @c DUID object depending on the identifier type.
    ///
    /// @param identifier Pointer to the binary value holding an identifier.
    /// @param identifier_len Length of the identifier.
    /// @param identifier_type Type of the identifier (hardware address or
    /// DUID).
    /// @param ipv4_subnet_id Identifier of the IPv4 subnet to which the host
    /// is connected.
    /// @param ipv6_subnet_id Identifier of the IPv6 subnet to which the host
    /// is connected.
    /// @param ipv4_reservation An IPv4 address reserved for the client. If
    /// this address is set to 0, there is no reservation.
    /// @param hostname Hostname to be allocated to both DHCPv4 and DHCPv6
    /// clients. This is empty string if hostname is not allocated.
205 206 207 208
    /// @param dhcp4_client_classes A string holding DHCPv4 client class names
    /// separated by commas. The names get trimmed by this constructor.
    /// @param dhcp6_client_classes A string holding DHCPv6 client class names
    /// separated by commas. The names get trimmed by this constructor.
209 210 211
    ///
    /// @throw BadValue if the provided values are invalid. In particular,
    /// if the identifier is invalid.
212 213 214 215
    Host(const uint8_t* identifier, const size_t identifier_len,
         const IdentifierType& identifier_type,
         const SubnetID ipv4_subnet_id, const SubnetID ipv6_subnet_id,
         const asiolink::IOAddress& ipv4_reservation,
216 217 218
         const std::string& hostname = "",
         const std::string& dhcp4_client_classes = "",
         const std::string& dhcp6_client_classes = "");
219

220 221 222 223 224 225
    /// @brief Constructor.
    ///
    /// Creates @c Host object using an identifier in a textual format. This
    /// is useful in cases when the reservation is specified in the server
    /// configuration file, where:
    /// - MAC address is specified as: "01:02:03:04:05:06"
226 227 228 229 230 231
    /// - DUID can be specified as: "01:02:03:04:05:06:ab:cd" or "010203040506abcd".
    /// - Other identifiers are specified as: "010203040506abcd" or as
    /// "'some identfier'".
    ///
    /// In case of identifiers other than HW address and DUID it is possible to use
    /// textual representation, e.g. 'some identifier', which is converted to a
232
    /// vector of ASCII codes representing characters in a given string, excluding
233 234
    /// quotes. This is useful in cases when specific identifiers, e.g. circuit-id
    /// are manually assigned user friendly values.
235
    ///
236
    /// @param identifier Identifier in the textual format. The expected formats
237 238
    /// for the hardware address and other identifiers are provided above.
    /// @param identifier_name One of "hw-address", "duid", "circuit-id".
239 240 241 242 243 244 245 246
    /// @param ipv4_subnet_id Identifier of the IPv4 subnet to which the host
    /// is connected.
    /// @param ipv6_subnet_id Identifier of the IPv6 subnet to which the host
    /// is connected.
    /// @param ipv4_reservation An IPv4 address reserved for the client. If
    /// this address is set to 0, there is no reservation.
    /// @param hostname Hostname to be allocated to both DHCPv4 and DHCPv6
    /// clients. This is empty string if hostname is not allocated.
247 248 249 250
    /// @param dhcp4_client_classes A string holding DHCPv4 client class names
    /// separated by commas. The names get trimmed by this constructor.
    /// @param dhcp6_client_classes A string holding DHCPv6 client class names
    /// separated by commas. The names get trimmed by this constructor.
251 252 253
    ///
    /// @throw BadValue if the provided values are invalid. In particular,
    /// if the identifier is invalid.
254 255 256
    Host(const std::string& identifier, const std::string& identifier_name,
         const SubnetID ipv4_subnet_id, const SubnetID ipv6_subnet_id,
         const asiolink::IOAddress& ipv4_reservation,
257 258 259
         const std::string& hostname = "",
         const std::string& dhcp4_client_classes = "",
         const std::string& dhcp6_client_classes = "");
260

261 262
    /// @brief Replaces currently used identifier with a new identifier.
    ///
263
    /// This method sets a new identifier type and value for a host.
264
    /// This method is called by the @c Host constructor.
265
    ///
266
    /// @param identifier Pointer to a buffer holding an identifier.
267 268 269 270 271 272 273 274 275
    /// @param len Length of the identifier that the @c identifier points to.
    /// @param type Identifier type.
    ///
    /// @throw BadValue if the identifier is invalid.
    void setIdentifier(const uint8_t* identifier, const size_t len,
                       const IdentifierType& type);

    /// @brief Replaces currently used identifier with a new identifier.
    ///
276
    /// This method sets a new identifier type and value for a host.
277
    /// This method is called by the @c Host constructor.
278
    ///
279 280
    /// @param identifier Reference to a new identifier in the textual format.
    /// @param name One of "hw-address", "duid", "circuit-id".
281 282
    ///
    /// @throw BadValue if the identifier is invalid.
283 284
    void setIdentifier(const std::string& identifier, const std::string& name);

285 286 287 288
    /// @brief Returns hardware address for which the reservations are made.
    ///
    /// @return Pointer to the @c HWAddr structure or null if the reservation
    /// is not associated with a hardware address.
289
    HWAddrPtr getHWAddress() const;
290

291
    /// @brief Returns DUID for which the reservations are made.
292 293 294
    ///
    /// @return Pointer to the @c DUID structure or null if the reservation
    /// is not associated with a DUID.
295
    DuidPtr getDuid() const;
296

297 298 299 300
    /// @brief Returns the identifier in a binary form.
    ///
    /// @return const reference to a vector<uint8_t> holding an identifier
    /// value.
301 302
    const std::vector<uint8_t>& getIdentifier() const;

303
    /// @brief Returns the identifier type.
304
    ///
305 306
    IdentifierType getIdentifierType() const;

307 308 309
    /// @brief Returns host identifier in a textual form.
    ///
    /// @return Identifier in the form of <type>=<value>.
310 311
    std::string getIdentifierAsText() const;

312 313 314
    /// @brief Returns name of the identifier of a specified type.
    static std::string getIdentifierName(const IdentifierType& type);

315 316 317 318 319 320 321 322 323 324
    /// @brief Returns host identifier in textual form.
    ///
    /// @param type Identifier type.
    /// @param value Pointer to a buffer holding identifier.
    /// @param length Length of the identifier.
    /// @return Identifier in the form of <type>=<value>.
    static std::string getIdentifierAsText(const IdentifierType& type,
                                           const uint8_t* value,
                                           const size_t length);

325 326 327 328 329 330 331 332 333 334 335 336 337 338
    /// @brief Sets new IPv4 subnet identifier.
    ///
    /// @param ipv4_subnet_id New subnet identifier.
    void setIPv4SubnetID(const SubnetID ipv4_subnet_id) {
        ipv4_subnet_id_ = ipv4_subnet_id;
    }

    /// @brief Sets new IPv6 subnet identifier.
    ///
    /// @param ipv6_subnet_id New subnet identifier.
    void setIPv6SubnetID(const SubnetID ipv6_subnet_id) {
        ipv6_subnet_id_ = ipv6_subnet_id;
    }

339
    /// @brief Returns subnet identifier for IPv4 reservation.
340 341 342 343
    SubnetID getIPv4SubnetID() const {
        return (ipv4_subnet_id_);
    }

344
    /// @brief Returns subnet identifier for IPv6 reservations.
345 346 347 348
    SubnetID getIPv6SubnetID() const {
        return (ipv6_subnet_id_);
    }

349 350 351 352 353
    /// @brief Sets new IPv4 reservation.
    ///
    /// The new reservation removes a previous reservation.
    ///
    /// @param address Address to be reserved for the client.
354
    ///
355 356
    /// @throw isc::BadValue if the provided address is not an IPv4 address,
    /// is a 0 address or broadcast address.
357
    void setIPv4Reservation(const asiolink::IOAddress& address);
358

359 360 361 362 363
    /// @brief Removes the IPv4 reservation.
    ///
    /// Sets the IPv4 reserved address to 0.
    void removeIPv4Reservation();

364 365 366
    /// @brief Returns reserved IPv4 address.
    ///
    /// @return IPv4 address or 0.0.0.0 if no IPv4 reservation specified.
367 368 369 370
    const asiolink::IOAddress& getIPv4Reservation() const {
        return (ipv4_reservation_);
    }

371 372 373 374 375 376 377 378 379 380 381 382
    /// @brief Adds new IPv6 reservation.
    ///
    /// @param reservation New IPv6 reservation to be appended.
    void addReservation(const IPv6Resrv& reservation);

    /// @brief Returns IPv6 reservations of a specified type.
    ///
    /// @param type Type of the reservations to be returned (NA or PD).
    ///
    /// @return A range of iterators pointing to the reservations of
    /// the specified type.
    IPv6ResrvRange getIPv6Reservations(const IPv6Resrv::Type& type) const;
383

384 385 386 387 388 389
    /// @brief Returns all IPv6 reservations.
    ///
    /// @return A range of iterators pointing to the reservations of
    /// the specified type.
    IPv6ResrvRange getIPv6Reservations() const;

390 391 392 393 394
    /// @brief Checks if there is at least one IPv6 reservation for this host.
    ///
    /// @return true if there is a reservation for the host, false otherwise.
    bool hasIPv6Reservation() const;

395 396 397 398 399 400 401 402
    /// @brief Checks if specified IPv6 reservation exists for the host.
    ///
    /// @param reservation A reservation to be checked for the host.
    ///
    /// @return true if the reservation already exists for the host, false
    /// otherwise.
    bool hasReservation(const IPv6Resrv& reservation) const;

403 404 405 406 407 408 409
    /// @brief Sets new hostname.
    ///
    /// @param hostname New hostname.
    void setHostname(const std::string& hostname) {
        hostname_ = hostname;
    }

410
    /// @brief Returns reserved hostname.
411 412 413 414
    const std::string& getHostname() const {
        return (hostname_);
    }

415 416 417
    /// @brief Adds new client class for DHCPv4.
    ///
    /// @param class_name Class name.
418
    void addClientClass4(const std::string& class_name);
419

420
    /// @brief Returns classes which DHCPv4 client is associated with.
421 422 423 424
    const ClientClasses& getClientClasses4() const {
        return (dhcp4_client_classes_);
    }

425 426 427
    /// @brief Adds new client class for DHCPv6.
    ///
    /// @param class_name Class name.
428
    void addClientClass6(const std::string& class_name);
429

430
    /// @brief Returns classes which DHCPv6 client is associated with.
431 432 433 434
    const ClientClasses& getClientClasses6() const {
        return (dhcp6_client_classes_);
    }

435 436
    /// @brief Returns pointer to the DHCPv4 option data configuration for
    /// this host.
437 438 439
    ///
    /// Returned pointer can be used to add, remove and udate options
    /// reserved for a host.
440 441 442 443 444 445 446 447 448 449 450 451
    CfgOptionPtr getCfgOption4() {
        return (cfg_option4_);
    }

    /// @brief Returns const pointer to the DHCPv4 option data configuration for
    /// this host.
    ConstCfgOptionPtr getCfgOption4() const {
        return (cfg_option4_);
    }

    /// @brief Returns pointer to the DHCPv6 option data configuration for
    /// this host.
452 453 454
    ///
    /// Returned pointer can be used to add, remove and udate options
    /// reserved for a host.
455 456 457 458 459 460 461 462 463 464
    CfgOptionPtr getCfgOption6() {
        return (cfg_option6_);
    }

    /// @brief Returns const pointer to the DHCPv6 option data configuration for
    /// this host.
    ConstCfgOptionPtr getCfgOption6() const {
        return (cfg_option6_);
    }

465 466 467
    /// @brief Returns information about the host in the textual format.
    std::string toText() const;

Tomek Mrugalski's avatar
Tomek Mrugalski committed
468 469 470 471 472 473 474 475 476 477 478 479
    /// @brief Sets Host ID (primary key in MySQL and Postgres backends)
    /// @param id HostId value
    void setHostId(HostID id) {
        host_id_ = id;
    }

    /// @brief Returns Host ID (primary key in MySQL and Postgres backends)
    /// @return id HostId value (or 0 if not set)
    HostID getHostId() const {
        return (host_id_);
    }

480 481
private:

482 483 484 485 486 487 488 489 490 491 492 493 494
    /// @brief Adds new client class for DHCPv4 or DHCPv6.
    ///
    /// This method is called internally by the @c addClientClass4 and
    /// @c addClientClass6 functions. It adds the class of the specified name
    /// to the supplied class set. The class names are trimmed before they are
    /// added. Empty class names are ignored.
    ///
    /// @param [out] classes Set of classes to which the new class should be
    /// inserted.
    /// @param class_name Class name.
    void addClientClassInternal(ClientClasses& classes,
                                const std::string& class_name);

495 496 497 498
    /// @brief Identifier type.
    IdentifierType identifier_type_;
    /// @brief Vector holding identifier value.
    std::vector<uint8_t> identifier_value_;
499
    /// @brief Subnet identifier for the DHCPv4 client.
500
    SubnetID ipv4_subnet_id_;
501
    /// @brief Subnet identifier for the DHCPv6 client.
502
    SubnetID ipv6_subnet_id_;
503
    /// @brief Reserved IPv4 address.
504
    asiolink::IOAddress ipv4_reservation_;
505
    /// @brief Collection of IPv6 reservations for the host.
506
    IPv6ResrvCollection ipv6_reservations_;
507
    /// @brief Name reserved for the host.
508
    std::string hostname_;
509
    /// @brief Collection of classes associated with a DHCPv4 client.
510
    ClientClasses dhcp4_client_classes_;
511
    /// @brief Collection of classes associated with a DHCPv6 client.
512
    ClientClasses dhcp6_client_classes_;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
513 514 515 516

    /// @brief HostID (a unique identifier assigned when the host is stored in
    ///                MySQL or Pgsql)
    uint64_t host_id_;
517

518 519 520 521
    /// @brief Pointer to the DHCPv4 option data configuration for this host.
    CfgOptionPtr cfg_option4_;
    /// @brief Pointer to the DHCPv6 option data configuration for this host.
    CfgOptionPtr cfg_option6_;
522 523
};

524 525 526 527 528 529 530 531 532 533 534 535
/// @brief Pointer to the @c Host object.
typedef boost::shared_ptr<Host> HostPtr;

/// @brief Const pointer to the @c Host object.
typedef boost::shared_ptr<const Host> ConstHostPtr;

/// @brief Collection of the const Host objects.
typedef std::vector<ConstHostPtr> ConstHostCollection;

/// @brief Collection of the @c Host objects.
typedef std::vector<HostPtr> HostCollection;

536 537 538 539
}
}

#endif // HOST_H