123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479 |
- // Copyright (C) 2012-2016 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/.
- /**
- @page libdhcpsrv libdhcpsrv - Server DHCP library
- This library contains code used for the DHCPv4 and DHCPv6 servers' operations,
- including the "Lease Manager" that manages information about leases and the
- "Configuration Manager" that stores the servers' configuration etc.
- The code here is server specific. For generic (useful to the server,
- client, relay and other tools like perfdhcp) code, please see
- \ref libdhcp.
- This library contains several crucial elements for the operation of the DHCP server:
- - isc::dhcp::LeaseMgr - lease manager is the name for the database backend that stores
- leases.
- - isc::dhcp::CfgMgr - configuration manager that holds DHCP specific
- configuration information (subnets, pools, options, timer values etc.) in
- easy to use format.
- - isc::dhcp::AllocEngine - allocation engine that handles new requests and allocates new
- leases.
- - isc::dhcp::HostMgr - manager for static reservations (a.k.a. host reservations).
- - isc::dhcp::D2ClientMgr - DHCP-DDNS (D2) client manager which is responsible for
- the communication between the DHCP server and the D2 component.
- - isc::dhcp::Dhcp4o6IpcBase - common part (base class) of DHCPv4-over-DHCPv6
- inter server communication (aka IPC).
- @section leasemgr Lease Manager
- LeaseMgr provides a common, unified abstract API for all database backends. All
- backends are derived from the base class isc::dhcp::LeaseMgr. Currently Kea
- supports three backends, implemented in the following classes:
- - isc::dhcp::Memfile_LeaseMgr - stores leases in a CSV file,
- - isc::dhcp::MySqlLeaseMgr - stores leases in a MySQL database
- - isc::dhcp::PgSqlLeaseMgr - stores leases in a PostgreSQL database
- @section cfgmgr Configuration Manager
- Configuration Manager (\ref isc::dhcp::CfgMgr) is a singleton object which
- holds configuration information necessary for the operation of Kea daemons.
- A complete collection of information for the daemon is stored in the
- \ref isc::dhcp::SrvConfig object. Internally, the Configuration Manager
- holds a list of \ref isc::dhcp::SrvConfig objects, from which one
- is marked as "current configuration".
- When the server starts up or is being reconfigured a new
- \ref isc::dhcp::SrvConfig object, referred to as "staging configuration",
- is created. The staging configuration is held at the tip of the list of
- configurations. The object can be accessed by calling the
- \ref isc::dhcp::CfgMgr::getStagingCfg. This object can be accessed
- from different stages of the configuration parsing and modified as needed.
- Modifications of the staging configuration do not affect the current
- configuration. The staging configuration is unused until the
- \ref isc::dhcp::CfgMgr::commit function is called. This exception safe method
- marks the staging object as "current configuration". The const pointer to the
- current configuration can be accessed by calling a
- \ref isc::dhcp::CfgMgr::getCurrentCfg.
- The staging configuration can be discarded at any time before it is committed
- by calling the \ref isc::dhcp::CfgMgr::rollback. This removes the
- \ref isc::dhcp::SrvConfig object from the Configuration Manager. When
- the \ref isc::dhcp::CfgMgr::getStagingCfg is called again a fresh/default
- \ref isc::dhcp::SrvConfig object is returned.
- The Configuration Manager stores previous configurations, i.e. configurations
- which occurred prior to the most current configuration. This is currently
- unused (except for unit tests) by the daemons, but in the future this
- mechanism can be used to trigger a rollover of the server configuration
- to a last good configuration that the administrator prefers.
- The previous configurations are identified by the value which specifies a
- distance between the current configuration and the previous
- configuration. For example: the value of 1 identifies an immediate
- predecessor of the current configuration, the value of 2 identifies the
- one that occurred before it etc.
- @section hostmgr Host Manager
- Host Manager implemented by the \ref isc::dhcp::HostMgr is a singleton object
- which provides means to retrieve resources statically assigned to the DHCP
- clients, such as IP addresses, prefixes or hostnames. The statically assigned
- resources are called reservations (or host reservations) and they are
- represented in the code by the \ref isc::dhcp::Host class.
- The reservations can be specified in the configuration file or in some
- other storage (typically in a database). A dedicated object, called
- host data source, is needed to retrieve the host reservations from the
- database. This object must implement the \ref isc::dhcp::BaseHostDataSource
- interface and its implementation is specific to the type of storage
- holding the reservations. For example, the host data source managing
- host reservations in the MySQL database is required to establish
- connection to the MySQL database and issue specific queries. Once
- implemented, the \ref isc::dhcp::HostMgr::create method must be updated
- to create an instance of this datasource. Note, that this instance is
- created as "alternate host data source" as opposed to the primary data
- source which returns host reservations specified in the configuration file.
- The primary data source is implemented internally in the
- \ref isc::dhcp::HostMgr and uses the configuration data structures held by
- the \ref isc::dhcp::CfgMgr to retrieve the reservations. In general, the
- \ref isc::dhcp::HostMgr first searches for the reservations using the
- primary data source and falls back to the use of alternate data source
- when nothing has been found. For those methods which are meant to return
- multiple reservations (e.g. find all reservations for the particular
- client), the \ref isc::dhcp::HostMgr will use both primary and alternate
- data source (if present) and concatenate results.
- For more information about the \ref isc::dhcp::HostMgr please refer to its
- documentation.
- @subsection postgreSQLHostMgr PostgreSQL Host Reservation Management
- Storing and retrieving host reservations within a PostgreSQL schema is
- provided by the class, \ref isc::dhcp::PgSqlHostDataSource, a derivation of
- \ref isc::dhcp::BaseHostDataSource and is depicted in the following
- class diagram:
- @image html pgsql_host_data_source.svg "PgSqlHostDataSource Class Diagram"
- @section optionsConfig Options Configuration Information
- The \ref isc::dhcp::CfgOption object holds a collection of options being
- sent to the client. Since each subnet comes with a distinct set of
- options, every \ref isc::dhcp::Subnet object holds its own copy of the
- \ref isc::dhcp::CfgOption object with specific options.
- The DHCP server also allows for configuration of "global" options
- which are shared by all subnets. The rule here is that if a particular
- option appears in the global options set and the subnet specific options
- set, the subnet specific option takes precedence. The global options
- configuration is held in the dedicated instance of the
- \ref isc::dhcp::CfgOption class. This instance is owned by the
- \ref isc::dhcp::SrvConfig class.
- When the new configuration is parsed, the global options are merged into
- the \ref isc::dhcp::CfgOption instances for all subnets. This is
- causing some overhead during the reconfiguration of the server but on
- the other hand it avoids the lookup of options in two places (among
- subnet specific options and global options) during each packet
- processing.
- One of the benefits of keeping a separate set of global options is
- that there may be cases when the server administrator doesn't specify
- any subnet configuration and only wants global options to be used.
- This is the case, when the DHCP server is used for stateless
- configuration, i.e. client's are not allocated an address or prefix,
- and only stateless configuration is handed out.
- @section allocengine Allocation Engine
- Allocation Engine (\ref isc::dhcp::AllocEngine) is what its name say - an engine
- that handles allocation of new leases. It takes parameters that the client
- provided (client-id, DUID, subnet, a hint if the user provided one, etc.) and
- then attempts to allocate a lease.
- There is no single best solution to the address assignment problem. Server
- is expected to pick an address from its available pools is currently not used.
- There are many possible algorithms that can do that, each with its own advantages
- and drawbacks. This allocation engine must provide robust operation is radically
- different scenarios, so there address selection problem was abstracted into
- separate module, called allocator. Its sole purpose is to pick an address from
- a pool. Allocation engine will then check if the picked address is free and if
- it is not, then will ask allocator to pick again.
- At least 3 allocators will be implemented:
- - Iterative - it iterates over all resources (addresses or prefixes) in
- available pools, one by one. The advantages of this approach are: speed
- (typically it only needs to increase address just one), the guarantee to cover
- all addresses and predictability. This allocator behaves reasonably good in
- case of nearing depletion. Even when pools are almost completely allocated, it
- still will be able to allocate outstanding leases efficiently. Predictability
- can also be considered a serious flaw in some environments, as prediction of the
- next address is trivial and can be leveraged by an attacker. Another drawback of
- this allocator is that it does not attempt to give the same address to returning
- clients (clients that released or expired their leases and are requesting a new
- lease will likely to get a different lease). This allocator is not suitable for
- temporary addresses, which must be randomized. This allocator is implemented
- in \ref isc::dhcp::AllocEngine::IterativeAllocator.
- - Hashed - ISC-DHCP uses hash of the client-id or DUID to determine, which
- address is tried first. If that address is not available, the result is hashed
- again. That procedure is repeated until available address is found or there
- are no more addresses left. The benefit of that approach is that it provides
- a relative lease stability, so returning old clients are likely to get the same
- address again. The drawbacks are increased computation cost, as each iteration
- requires use of a hashing function. That is especially difficult when the
- pools are almost depleted. It also may be difficult to guarantee that the
- repeated hashing will iterate over all available addresses in all pools. Flawed
- hash algorithm can go into cycles that iterate over only part of the addresses.
- It is difficult to detect such issues as only some initial seed (client-id
- or DUID) values may trigger short cycles. This allocator is currently not
- implemented. This will be the only allocator allowed for temporary addresses.
- - Random - Another possible approach to address selection is randomization. This
- allocator can pick an address randomly from the configured pool. The benefit
- of this approach is that it is easy to implement and makes attacks based on
- address prediction more difficult. The drawback of this approach is that
- returning clients are almost guaranteed to get a different address. Another
- drawback is that with almost depleted pools it is increasingly difficult to
- "guess" an address that is free. This allocator is currently not implemented.
- @subsection allocEngineTypes Different lease types support
- Allocation Engine has been extended to support different types of leases. Four
- types are supported: TYPE_V4 (IPv4 addresses), TYPE_NA (normal IPv6 addresses),
- TYPE_TA (temporary IPv6 addresses) and TYPE_PD (delegated prefixes). Support for
- TYPE_TA is partial. Some routines are able to handle it, while other are
- not. The major missing piece is the RandomAllocator, so there is no way to randomly
- generate an address. This defeats the purpose of using temporary addresses for now.
- @subsection allocEnginePD Prefix Delegation support in AllocEngine
- The Allocation Engine supports allocation of the IPv6 addresses and prefixes.
- For a prefix pool, the iterative allocator "walks over"
- every available pool. It is similar to how it iterates over address pool,
- but instead of increasing address by just one, it walks over the whole delegated
- prefix length in one step. This is implemented in
- isc::dhcp::AllocEngine::IterativeAllocator::increasePrefix(). Functionally the
- increaseAddress(addr) call is equivalent to increasePrefix(addr, 128)
- (increasing by a /128 prefix, i.e. a single address). However, both methods are
- kept, because increaseAddress() is faster and this is a routine that may be
- called many hundred thousands times per second.
- @subsection allocEngineDHCPv4HostReservation Host Reservation support
- The Allocation Engine supports allocation of statically assigned addresses
- to the DHCPv4 clients, a.k.a. Host Reservation.
- When the server receives a DHCPDISCOVER or DHCPREQUEST from the client it
- calls \ref isc::dhcp::AllocEngine::allocateLease4 to obtain the suitable lease
- for the client. If the Allocation Engine determines that the particular client
- has a reservation it will try to allocate a reserved address for it. If the
- client requested allocation or renewal of a different address, the Allocation
- Engine will respond with a NULL lease to indicate that the address
- desired by the client could not be assigned. The DHCP server should send
- a DHCPNAK to the client and the client should fall back to the DHCP
- server discovery. When the client sends DHCPDISCOVER, the Allocation
- Engine offers the reserved address and the client should request the
- offered address in subsequent DHCPREQUEST messages.
- There are cases when the Allocation Engine is unable to assign the
- reserved address for the client. This includes the situations when
- the address had been previously reserved for another client or the
- address had been assigned out of the dynamic address pool. Such address
- may still remain in use of the client which obtained it first and the
- Allocation Engine must not assign it to the client for which it is
- reserved until the client using this address releases or the server
- assigns a different address for it.
- In order to resolve this conflict the Allocation Engine will refuse to
- renew the lease for the client using the address not reserved for it.
- This client should fall back to the 4-way exchange and the Allocation
- Engine will assign a different address. As a result, the reserved
- address will be freed for the use of the client for which the reservation
- was made. The client will be offered/allocated a reserved address
- the next time it retries sending a DHCPDISCOVER/DHCPREQUEST message to
- the server.
- @section timerManager Timer Manager
- The fundamental role of the DHCP server is to receive and process DHCP
- messages received over the sockets opened on network interfaces. The
- servers' include the main loops in which the servers passively wait
- for the messages. This is done by calling the
- @c isc::dhcp::IfaceMgr::receive4 and/or @c isc::dhcp::IfaceMgr::receive6
- methods for DHCPv4 and DHCPv6 server respectively. Internally, these
- methods call @c select() on open sockets, which blocks for a
- specified amount of time.
- The implication of using the @c select() is that the server has no
- means to process any "events" while it is waiting for the @c select()
- to return. An example of such an event is the expiration of the timer
- which controls when the server should detect and process expired
- leases.
- The @c isc::dhcp::TimerMgr has been created to address the issue of
- processing expired leases according to the the dedicated timer.
- Nevertheless, this concept is universal and should be used for
- all timers which need to be triggered asynchronously, i.e. independently
- from processing the DHCP messages.
- The @c TimerMgr allows for registering timers and associating them with
- user callback functions, which are executed without waiting for the
- call to the @c select() function to return as a result of the timeout.
- When the particular timer elapses, the blocking call to select is
- interrupted by sending data over a dedicated (for a timer)
- @c isc::util::WatchSocket. Each timer has an instance of
- @c isc::util::WatchSocket associated with it, and each such socket
- is registered with the @c IfaceMgr using the @c IfaceMgr::addExternalSocket.
- When the transmission of the data over the watch socket interrupts the
- @c select() call, the user callback is executed by
- @c isc::dhcp::IfaceMgr and the watch socket is cleared to accept
- subsequent events for that particular timer.
- The timers are implemented using the @c isc::asiolink::IntervalTimer class.
- They are run in a dedicated thread which is owned (created and destroyed)
- by @c isc::dhcp::TimerMgr. This worker thread runs an instance
- of @c isc::asiolink::IOService object which is associated with all
- registered timers. The thread uses a common callback function which
- is executed when a timer elapses. This callback function receives
- a name of the elapsed timer as an argument and, based on that, selects the
- appropriate @c isc::util::WatchSocket to be marked as ready. In order to
- overcome the race conditions with the main thread, the worker thread blocks
- right after it marks the watch socket as ready, and waits for this
- socket to be cleared by the main thread. This is the indication
- that the timer specific callback function has been invoked and the
- worker thread may continue monitoring registered timers and signal
- their readiness when they elapse.
- @section leaseReclamationRoutine Leases Reclamation Routine
- Lease reclamation is the process in which the expired lease becomes
- available for re-assignment to the same or another client. When the
- server reclaims the lease it executes the callouts registered for the
- "lease4_expire" and "lease6_expire" hook points, performs the DNS update
- to remove any DNS records associated with the expired lease, and finally
- marks a lease as reclaimed in the lease database. The lease may be
- marked as reclaimed by setting its state to @c Lease::STATE_EXPIRED_RECLAIMED
- or by being removed from the database.
- Reclamation is performed periodically for a bulk of expired
- leases in the lease reclamation routine. The lease reclamation routines
- for both DHCP servers are implemented in the @c isc::dhcp::AllocEngine:
- - @c isc::dhcp::AllocEngine::reclaimExpiredLeases4 (DHCPv4)
- - @c isc::dhcp::AllocEngine::reclaimExpiredLeases6 (DHCPv6)
- Note that besides the reclamation of the leases, these methods also
- update the relevant statistics, i.e. decrease the number of assigned
- leases and increase the number of reclaimed leases.
- The reclamation routines are executed periodically according to
- the server configuration (see the documentation for the
- "expired-leases-processing" configuration map). Internally, they are
- registered as callback functions in the @c isc::dhcp::TimerMgr
- (see @ref timerManager for the details), during the servers' startup
- or reconfiguration.
- Execution of the reclamation routine may take a relatively
- long period of time. It depends on the complexity of the callouts,
- whether the DNS update is required for leases, and the type of the
- lease database used. While the reclamation routine is
- executed, the server will not process any DHCP messages to avoid
- race conditions being a result of concurrent access to the lease
- database to allocate and reclaim leases. To make sure that the
- server remains responsive, it is possible to limit the number of
- leases being processed by the leases reclamation routine and/or
- limit the time for the reclamation routine to process
- leases. Both limits are specified in the respective arguments
- passed to the lease reclamation routines.
- As mentioned above, reclaimed leases may be marked as such, by
- updating their state to @c Lease::STATE_EXPIRED_RECLAIMED or by
- being removed. This behavior is controlled by the boolean parameter
- passed to the reclamation routine. The first approach is desired
- when the server should provide "lease affinity", i.e. ability to
- re-assign the same lease to the returning client. By only
- updating the lease state, the server preserves association of the
- lease with a particular client. When that client returns the
- server may assign the same lease to the client, assuming that this
- lease is still available. The lease is removed during the
- reclamation when the lease affinity is not required and it is
- preferred to not keep redundant information (about expired
- leases) in the lease database.
- If the reclaimed leases are not removed, they are held in the
- database for a specified amount of time after their expiration.
- Each reclaimed lease is removed when this time elapses for it.
- The @c isc::dhcp::LeaseMgr::deleteExpiredReclaimedLeases4 and
- @c isc::dhcp::LeaseMgr::deleteExpiredReclaimedLeases6 are used
- to remove those leases for which the specified amount of time
- since expiration elapsed. These methods are executed periodically
- by the DHCP servers using the dedicated timers registered in the
- @c isc::dhcp::TimerMgr.
- @section subnetSelect Subnet Selection
- An important service offered by this library is the subnet selection
- from a query packet.
- @subsection dhcp4SubnetSelect DHCPv4 Subnet Selection
- Selectors (i.e., members of @c SubnetSelector class) are:
- - incoming interface name
- - gateway address - giaddr field
- - client address - ciaddr field
- - local address
- - remote address
- - option select - from the first Relay Agent Link Selection suboption or
- from a Subnet Selection option
- - client classes - used to reject a matching rule and try next rules
- First use the option select, next if the message was relayed (not undefined
- gateway address) use the gateway address as a subnet relay address.
- If a subnet was not already selected choose an address between:
- - if the gateway address is not undefined the gateway address
- - if the client address is not undefined and the local address not the
- broadcast address (i.e., renew or rebind) the client address
- - if the remote address is not undefined and the local address not the
- broadcast address (i.e., renew or rebind) the remote address
- - at this point try the interface name as a subnet interface
- - if the interface name does not select a subnet choose the interface address
- (last resort)
- Match the chosen address in a subnet address range.
- @subsection dhcp4o6SubnetSelect DHCPv4-over-DHCPv6 Subnet Selection
- Selectors (i.e., members of @c SubnetSelector class) are:
- - incoming interface name
- - gateway address - giaddr field (should be always undefined)
- - client address - ciaddr field
- - local address - set to the interface IPv4 address
- - remote address - IPv6 address
- - option select - from a Subnet Selection option
- - first relay link address - (IPv6) undefined or the first relay link
- address which is not undefined or link local (i.e., usable)
- - interface ID - (IPv6) when a relay message includes an interface ID
- relay option
- - client classes - used to reject a matching rule and try next rules
- Check if DHCPv4-over-DHCPv6 is enabled for this particular subnet and
- continue with the next subnet is if it is not.
- First the remote address is matched in a subnet IPv6 range, second
- the interface ID if it is set is matched, third the interface name.
- These rules are applied for each subnet configuration so if two
- subnets match the first one is returned (vs. the first matching rule).
- @todo better DHCPv4-over-DHCPv6 selection, e.g., handle relayed
- messages and return best (vs first) match.
- @subsection dhcp6SubnetSelection DHCPv6 Subnet Selection
- Selectors (i.e., members of @c SubnetSelector class) are:
- - incoming interface name
- - remote address
- - first relay link address - undefined or the first relay link address which
- is not undefined or link local (i.e., usable)
- - interface ID - when a relay message includes an interface ID relay option
- - client classes - used to reject a matching rule and try next rules
- If the first relay link address is undefined the client is directly connected:
- the interface name is matched and if it does not select a subnet the remote
- address is matched in a subnet address range.
- If the first relay link address is not undefined the query was relayed:
- the interface ID is tried and if it does not select a subnet the first
- relay address is matched as a subnet relay address.
- @section dhcp4o6Ipc DHCPv4-over-DHCPv6 Inter Process Communication
- DHCPv4-over-DHCPv6 support is implemented using cooperating
- DHCPv6 and DHCPv6 servers. Servers communicate over a pair of
- local UDP sockets using consecutive ports. The common part of
- the Inter Process Communication (IPC) is provided by the base class
- @c isc::dhcp::Dhcp4o6IpcBase.
- The receiving interface name and remote IPv6 address meta information
- are conveyed within a Vendor Specific Information option with the ISC
- enterprise ID carrying interface and remote address suboptions.
- \ref isc::dhcp::Dhcp4o6IpcBase::send adds them,
- \ref isc::dhcp::Dhcp4o6IpcBase::receive decodes and removes them.
- Also see \ref dhcpv4o6Dhcp4 and \ref dhcpv4o6Dhcp6 for details on how IPC
- is used by DHCPv4 and DHCPv6 components.
- @todo
- DHCPv4-over-DHCPv6 which are relayed by a DHCPv6 relay are not yet supported.
- */
|