This document describes a design to extend Kea capabilities with Radius support.


The following goals are sought after in this design:

  1. Assign specific static addresses to some clients as provided by Radius.
  2. Assign other clients to specific pools as provided by Radius.
  3. Retrieve client information from Radius using authentication mechanism (Access-Request and Access-Accept / Access-Reject messages).
  4. Support accounting using Radius accounting mechanism.
  5. Limit number of authentication exchanges with Radius to absolute minimum.
  6. Be able to handle multiple Radius servers (at least two for authentication and at least two for accounting).
  7. Due to business reasons, the initial focus is on IPv4. IPv6 support will be added at a later stage.
  8. The primary OSes used for this project are CentOS 7 and RedHat 7. Testing on other systems may be done on best effort basis.


  1. Access control using Radius. The Kea DHCP server will be extended to allow contacting a RADIUS server every time a new packet comes in to determine whether or not to assign an address, and to get the IP address assignment or subnet to use from the RADIUS server, using the following algorithm:
  1. Upon receiving a packet (e.g. DHCPDISCOVER) from a new client, Kea will send Access-Request to the Radius server including "remote-id" and/or "circuit-id" value provided in DHCP option 82. Note: Kea will allow via configuration to choose which AVP to send to the Radius Server, and allow, to add Static AVP.
  1. Depending on the RADIUS server response, Kea will take one of three actions: a) pick a specific pool based on the Framed-Pool, b) use the Framed-IP-Address from the RADIUS response or reject assignment (if Access-Reject was received).
  1. If Access-Accept contains a User-Class attribute Kea will conduct special processing explained below. If the User-Class attribute is not present or is empty, Kea will continue normal packet processing.

The User-Class attribute returning from the Radius server will contain 5 or 6 comma separated fields.

  • BW = Information field
  • Pool-Name = The name of the client class assigned to the User (informational Field)
  • IP-Static = The IP assign to the user, if it static (informational field)
  • Subnet-Id = needed to assign to a static_ip, if the return attribute contain Static IP
  • VAS – Information field

There may be two more mutually exclusive fields:

  • Framed-Pool – The same as the Pool-Name, uses to assign a MAC/Remote-ID to a specific class name.
  • Framed-IP-Address – The IP assign to the User, if there is no Framed-Pool attribute, combined with the Subnet-Id, allow the Kea to assign static IP -> insert into kea host table.
  1. The Radius interface will be implemented as host data source. The information will be returned as Host reservation information. Host class will be extended to store additional information (“user context”) that will convey necessary Radius attributes that are returned in Access-Accept and are later needed when sending Accounting-request.
  1. Accounting using Radius. Kea will notify RADIUS server about the address leases being assigned, renewed, released or expired. Upon receiving a DHCPREQUEST from a client requesting an assignment of a new lease (not a renewing or rebinding client), Kea will send Accounting-Request with Acct-Status-Type set to "Start" to the Radius server. If the DHCPREQUEST is received from the renewing (or rebinding) client, Kea will send Accounting-Request with Acct-Status-Type set to "Interim-Update" instead. Upon receiving a DHCPRELEASE from a client, Kea will send Accounting- Request with Acct-Status-Type set to "Stop" to the Radius server. Also, the same packet with the same Acct-Status-Type value will be sent when the lease is expired.

The accounting information will be sent as Accounting-Request message with the following information:

  1. User-Name=value of DHCP option 82 (value inserted by the relay)
  2. Framed-IP-Address=IPv4 (IPv4 address assigned by Kea)
  3. User-Class=User-Class (value returned by RADIUS in Access-Accept message)
  4. Filter-ID=Filter-ID (value returned by RADIUS in Access-Accept message)
  5. Connect-Info=MAC address (value set by the client)
  6. Acct-Session-ID=MAC address;IPv4 address;value of DHCP option 82
  1. Host caching. Radius communication has significant impact on performance, therefore Radius responses for Access-Request must be cached. In Kea terminology, the Radius interface will be implemented as host backend and will return Host objects. A new mechanism to cache Host objects will be developed. The mechanism will have the following properties:
  1. It will be possible to configure Kea to use more than one host backends, with cache and Radius being two possible options. Kea will inspect the backends in order they are specified. If information is found in the first one (cache), the second one (Radius) is not looked up.
  1. It will be possible to tell Kea to put Host objects returned by a backed into a cache. This way for a given client, the Radius will be contacted only once and the response will be cached.
  1. To retain the cache information after server restart, the cache will be stored on disk in a text file. It is understood that the cache will be optimized for in-memory operation and reading large cache from disk may make the server start-up slower.
  1. There will be a very basic mechanism to control maximum size of the cache, expressed in number of hosts. This control mechanism will be optional. It will be possible to disable it, so Kea would never drop anything from a cache. This will ensure the Radius communication be kept to absolute minimum. It is understood that when used improperly, this may cause Kea to use more memory, so a machine with sufficient memory will be required.
  1. New commands will be implemented to manipulate the cache. At least the following commands will be implemented: cache-flush (removes all entries from the cache), cache-remove (removes a single entry from the cache).

The caching mechanism will ensure the Radius communication is kept to absolute minimum. However, if the information ever changes in Radius (e.g. a client has been promoted to from bronze to silver), Kea will continue using its outdated cache information. Cache-remove command will be used to notify Kea to discard obsolete cache information.

  1. Multiple IP relays per subnet. Kea 1.3 allows specifying a single IP address for a relay agent for each given subnet. This mechanism will be extended to allow specifying one or more addresses. The subnet will be selected if the relay address matches any value specified on the list and any client- class, if defined.
  1. Client-class on pools level. Kea 1.3 allows restricting access to subnets to specific client classes, but does not allow the same for pools. The code will be extended to allow restricting access to specific pools to packets belonging to specific user class.
  1. Backends in hooks. Existing backends are either enabled or disabled at compilation time. This approach has proven inflexible and we need to improve it. We will develop a registration mechanism, where any code, either from base Kea code or from a hook library, will be able to register and unregister a new backend type.
  1. Option defintions in hooks. Existing Kea 1.3 code provides support for many standard options and allows users to define additional option definitions as custom options. However, for a general purpose Radius hook, it will be useful to have option definitions defined in a hook. This means that the definitions should be honoured only when specific hook is loaded (otherwise the options should be treated as general, unknown option). This requires a change in how hooks are loaded when configuration is processed.


  1. When a new device shows in a network, it sends a DHCPDISCOVER packet. Kea will then parse (unpack) the packet, select a subnet for it and then check if the host for this particular client is available in each of configured backends. The backends will be configured as: cache, radius. Therfore, the first check will be whether host information is in a cache. If it is, that cached information will be used without contacting Radius. If it isn't, Kea will send Access-Request to the Radius server with the content of remote-id and/or circuit-id. Exact parameters to be sent will be configurable.
  1. Upon reception of Access-Accept, the backend will return Host object that contains specified address and/or pool. Other attributes received in Access-Accept will be stored in user context associated with this Host object. That returned Host object will be put in a cache. Any incoming packets coming with the same remote-id and/or circuit-id will use the cached information and will not involve Radius authorization exchanges.

All attributes returned in Access-Accept will be stored in user context. This ensures maximum flexibility.

  1. A host object returned by the Radius (or any "slow") backend will be added to a cache. This mechanism will be generic and could by applied to any backend that has performance limitations (Radius, but also MySQL, Postgres, Cassandra, but also possibly LDAP in the future). This cache will keep any number of hosts that were previously retrieved from a slow database in memory. This ensures that any follow up activities for this particular client (like DHCPRENEW or DHCPRELEASE processing) will be done using cached copy and will not require contacting the actual Radius server.
  1. Upon receiving DHCPREQUEST from a client requesting an assigned of a new lease (not a renewing or rebinding client), Kea will retrieve the Host stored in a cache and will use the Radius attributes stored in user context to send Accounting-Request with Acct-Status-Type set to "Start" to the Radius server. If this is a renewing or rebinding client, the Acct-Status-Type will be set to "Interim-Update" instead.
  1. Upon receiving DHCPRELEASE from a client, Kea will retrieve host from a cache and will use the information stored in the user context to send Accounting-Request with the Acct-Status-Type set to "Stop".


Type of Radius communication. After the Radius backend is implemented, Kea will be able to retrieve per client information from Radius. This can be used for two things. First, the ability to use Radius as access control for the network. Depending on Kea configuration, the clients that are not accepted by Radius, will not get an address. Second, it will provide the ability to provision specific addresses and/or pools on a per client basis. The client will be identified by its MAC address and value of one or more sub-options in option 82.

These two aspects or Radius communication have radically different characteristic. authentication is bidirectional, i.e. Kea will use the responses and change its behavior depending on its content. As such, this will be done in synchronous manner (or could use the new parking mechanism feature, but in general remain its synchronicity in the sense that the processing of a packet will not continue until a response comes in). Accounting is uni-directional, which means that Kea informs Radius about certain changes, but does not expect to get anything back. As such, this could be done asynchronously.

Storing Radius info in User Context. Information returned by the Radius server in Access-Accept message must be retained to be later used for sending Accounting-request messages. This information will be retained in Host objects. To ensure maximum flexibility, the additional information stored in hosts will be using the user context concept, already available in subnets and pools in Kea. The concept assumes that certain configuration elements may contain additional generic pieces of information. This can be anything as long as it is in JSON format. The Radius backend will store all attributes retrieved in Access-accept in the user context that will be attached to a Host object returned.

Configuration. The authentication and accounting features will be enabled/disabled independently. It will be possible to define which options and fields from the client package should be sent in either Access-Request. In particular, it will be possible to tell the library to use remote-id and/or circuit-id.

Details are TBD.


Multiple host data sources. As of Kea 1.3, it is possible to specify a single host data source, abeit the internal implementation always provides memory host data source to keep in memory host reservations that were defined in configuration file. This mechanism will be extended to support more than one host data source.

Host caching. A new mechanism will be developed to store in memory the hosts returned by any host data source. There will be a cache in memory that will keep host information about hosts retrieved from the actual host data source, such as Radius. If host information is available in the cache, the actual host data source (such as Radius) will not be contacted and the cached information will be used instead.

In many other software systems the information stored in a cache will be in general discarded during server shutdown. After restart, the cache is then slowly filled up again. However, in the Radius case, there is a significant complication. The original information sent by the relay agent (that includes circuit-id and/or remote-id may not be available, as client will send the renew messages directly to the server. As such, there is no easy way to query the Radius server again and refill the cache. Even if implemented a mechanism to store the relay information with leases, this would cause a spike of Radius queries after Kea restart. Obviously, we want to avoid that. Therefore it is necessary to have an ability to cache host information between restarts.

Caching control. Using cache mechanism improves host backend performance, but introduces some limitations. Without caching any changes to the actual host data source (e.g. Radius or MySQL) are immediately picked up by Kea, without any need for restarts or any notifications. If the information is cached and it is later updated in the backend, Kea will continue using its cached version and the updated information will be ignored. To avoid this problem, several new mechanisms will be implemented:

hr-cache-flush command - this command will discard existing cache completely, thus ensuring that the cache is populated with new updated information. After the cache is flushed, Kea will start sending Access-Request messages for new clients and will repopulate the cache. This command is useful if many changes were made in the Radius backend and the cached information should be discarded entirely.

hr-cache-delete command - this command will discard an information about a single client. This command is useful when a single client (or a small number of clients) have been updated. Other than those few, the other cached information is still valid.

Both commands will be available over REST interface, similar to other commands.

Cache will be enabled and disabled as a configuration parameter. Some users will prefer to keep the cache disabled to ensure that Kea always use the actual information. Others will prefer to have cache enabled to omit repeated calls to the Radius (or SQL) backend. Enabling or disabling cache will require Kea reconfiguration.

The cache will be implemented as additional HostContainer field that will be dedicated to caching.

There will be a simple FIFO list with a maximum cache size specified. When additional new host is being added to the cache, the oldest one is being removed. It will be possible to set this number to infinite, thus effectively removing cache removal.

One of the major problems to solve here is the problem of a disappearing cache after Kea shutdown/restart. If the cache content is lost after server restart, returning clients will send a DHCPSOLICIT(renew) packets that are unicasted directly to the server. This means they didn't pass through relay, so it's impossible to extract remote-id or circuit-id from option 82. The cache would need to write its content to a file and load content of that file upon start.

Details are TBD.

DESIGN: Registration of Host Backend Types

Details are TBD.


In a typical deployment, it is the relay agent, not the server, who is communicating with Radius (see RFC40414 or RFC7037). As such, it is useful for the Kea server to be able to interpret Radius DHCP options as inserted by relays. Nevertheless, it is also useful for the Radius hook to be able to translate Radius responses into DHCP options. This way there would be an unification to some degree regarding how Radius is handled in relay and server scenarios. Since this scenario is not strictly required by the primary user of this hook, it is considered low priority and marked as optional.

This should cover encoding RAI sub-option 7 (see RFC4014) for DHCPv4 and option 81 (see RFC7037) for DHCPv6.


This is still a work in progress.

An example configuration of the Radius backend will look as follows:

    "hosts-databases": [
            "type": "radius",
            "auth": [
                    // parameters to contact the first auth server
                    // parameters to contact the second auth server
            "accounting": [
                    // parameters to contact the first accounting server
                    // parameters to contact the second accounting server

  "hooks-libraries": [
         "library": "/opt/lib/",
         "parameters": {

             // This specifies whether the library should do the
             // access control using Radius authentication.
             "auth": true,

             // This specifies whether the library should do
             // accounting.
             "acct": true,

             // This specifies what kind of values should be taken from
             // the incoming DHCP packet and sent to Radius in the
             // Access-Request. This is an array, so multiple fields
             // can be used. The "value" field specifies an expression.
             // See Kea User's Guide (
             // .html#classification-using-expressions for details.
             "auth-attributes": [
                     // Take value of option 82 (RAI), take suboption 1
                     // (circuit-id)...
                     "value": "option[82].option[1].hex"

                     // ... and send it using attribute named Filter-id.
                     "attribute": "Filter-id"

             // Once the Access-Accept message comes back from the Radius
             // server, Kea will store all of its content (all attributes).
             // This list governs which fields should be sent back to the
             // Radius server when sending Accounting-Request.
             "acct-attributes": [
                 "send": [
                     { "attribute": "Filter-id" },
                     { "attribute": "BW" },
                     { "attribute": "VAS" }

Questions & Feedback

Q: One user commented: we sometimes need to reserve a user-class without subnetID. This is not possible with the current host reservation via mysql or postgres.

A: Radius doesn't have any specific concept of subnet-ids. We will leverage the usual host backend interface. The code in the backend will take the subnet-id and remember it, send the Access-Request, receive Access-Accept and then later add the remembered subnet-id.

Another user commented:

  • the client's MAC address should be available at least as 'Calling-Station-Id' or even better as 'User-Name' attribute (or both)
  • for the 'NAS-IP-Address' I would suggest the DHCP relay address (giaddr)
  • the Acct-Session-Id really has to be unique, it might include MAC/IP/Option-82, but that's not yet unique for 2 sessions for the same device with the same IP
  • it would be good to be able to build any RADIUS attribute based on an expression that incorporated lease configuration specific values. My use case is to build the 'NAS-Identifier' based on either the Option82.remote-id or if not available on the subnet's name (named pools or a name attribute for a pool in the KEA configuration would also be a good idea).

C: Implementor comment: in Radius the DHCP subnet-ID is the NAS port (SHOULD be in requests).

C: Should be attributes limited to types present in the dictionary? This introduces a hard constraint on the dictionary which is an external element, at the other hand there is nothing useful which can be done with an unknown attribute...


This work is being split into tickets that represent specific tasks. A great majority of them is expected to be completed in Kea 1.4 timeframe. A small number of non-critical tasks may be postponed to some later milestones.


  • #5524: Create stub Radius library - the library has to be created, needs to be aware of FreeRadius. The makefiles should disable the lib if FreeRadius is not detected.
  • #5525: Implement configuration storage and parsers - once the stub lib is created, we need to implement parser that will handle the configuration and store it in internal structures. No specific Radius interaction is needed.
  • #5526: Implement Radius communication
  • #5527: Host backend using Radius (use Frame-IP-Address attribute)
  • #5529: Ability to classify packet based on Radius response (use Framed-Pool attribute)
  • #5528: Mechanism for registering host data sources from a hook
  • #5530: Radius accounting


  • #5531: Multiple host backends
  • #5532: Caching host backend
  • #5533: Use caching host backend to actually cache hosts
  • #5534: cache-remove, cache-flush commands

Optional features:

  • #5536: Radius option defintions
  • #5537: Insert DHCP options based on Radius responses
  • #5516: mechanism to define options in hook libraries


  • #5425: Class restrictions on pool level
  • #5535: Multiple relay IP addresses per subnet
  • #5538: Documentation for users (with config examples)
  • #5539: Documentation for developers

Outstanding issues:

  • #5605: RADIUS library prints out RADIUS_ACCESS_NO_HOST_CACHE
  • #5608: There should be a way to send Password in all Access-Requests
  • 3: RADIUS: Print out list of access and accounting servers, similar to MySQL
  • 4: FLEX-ID not available when SUBNET4_SELECT is called

Last modified 16 months ago Last modified on Aug 2, 2018, 8:58:42 PM