Configure "device", "class" and "group" options
Beyond the global, network and subnet options already described, most sites will have a number of group or class based options, and have a requirement for setting reply parameters against individual devices.
In general, FreeRADIUS does not differentiate between "classes" (memberships defined by some attribute of the DHCP request) and "groups" (memberships defined by some manually aggregation related devices, typically based on lists of MAC address).
The sample DHCP configuration provided with FreeRADIUS makes use of an internal
attribute Group-Name to support the setting of different options for
different groups of devices.
In general the groups to which a device belongs is determined during the
processing of a request and these are added as instances of the
Group-Name attribute. This may be by performing a test on one or more
request parameters (akin to a "class"), hash-based lookup of up all of part of
an attribute in a local list (akin to a "subclass"), or doing the same using a
remote datastore (SQL, LDAP, REST API, etc).
FreeRADIUS can then iterate over Group-Name to set group-specific
options.
We describe some of these options in more detail.
Directly in Policy
Simple class options can be written directly into policy. This is most
suited to those options that rarely change and are based on attributes in the
request such as the User-Class.
Consider the ISC DHCP configuration snippet:
filename "undionly.kpxe";
class "pxeclient" {
match option substring(user-class,0,4);
}
subclass "pxeclient" "iPXE" {
filename "http://my.web.server/boot_script.php";
}
See also the isc_dhcp module, which can read a subset of the ISC DHCP configuration files.
Or the equivalent Kea configuration:
"Dhcp4": {
"option-data": [
{ "name": "boot-file-name", "data": "undionly.kpxe" }
],
"client-classes": [
{
"name": "pxeclient",
"test": "substring(option[77],0,4) == 'iPXE'",
"option-data": [
{
"name": "boot-file-name",
"data": "http://my.web.server/boot_script.php"
}
]
}
]
...
}
These define the "filename" DHCP option differently based on whether or not the supplied "user-class" option begins with "iPXE".
FreeRADIUS provides multiple ways for this to be configured.
For example, the following "unlang" policy implements the class options defined above:
if (User-Class && %str.subst(User-Class, 0, 4) == 'iPXE') {
reply.Boot-Filename := 'http://my.web.server/boot_script.php'
} else {
reply.Boot-Filename := 'undionly.kpxe'
}
Policy-based configuration of DHCP options is also useful for complex matching. For example, the following Unlang sets the Boot-Filename parameter based on the request’s Client-Identifier using regular expression captures, provided that it matches the given format:
if (Client-Identifier && \
"%{(string)Client-Identifier}" =~ /^RAS([0-9])-site([A-Z])$/) {
reply.Boot-Filename := "rasboot-%regex.match(1)-%regex.match(2).kpxe"
}
In Text Files
The files module that has already been described for global, network and
subnet options can also be used to apply options to groups of clients.
Firstly we must defined a mapping from a set of clients clients to their
respective groups. One option for this is to use the passwd module.
Create <raddb>/mods-enabled/dhcp_groups:
passwd dhcp_groups {
filename = ${modconfdir}/files/dhcp_groups
format = "~Group-Name:*,Client-Hardware-Address"
hash_size = 100
allow_multiple_keys = yes
delimiter = '|'
}
Then create <raddb>/mods-config/files/dhcp_groups
<group1 name>|<hardware address>,<hardware address>,<hardware address>
<group2 name>|<hardware address>,<hardware address>
i.e. one line for each group starting with the group name followed by a pipe character and then a comma-separated list of hardware addresses.
The allow_multiple_keys option allows for a host to be a member of
more than one group.
Having mapped the client to a group, an instance of files can be used to
add reply options.
Create an instance of files - <raddb>/mods-enabled/dhcp_group_options:
files dhcp_group_options {
filename = ${modconfdir}/files/dhcp_group_options
key = Group-Name
}
Then create the data file '<raddb>/mods-config/files/dhcp_group_options' containing entries with the group name as the key such as:
group1
Log-Server := 10.10.0.100,
LPR-Server := 10.10.0.200
group2
LPR-Server := 192.168.20.200
In the SQL Database
Policy and files are both read during startup and editing them while FreeRADIUS is running will not result in any changes in behaviour. If you require regular changes to DHCP options, then storing them in an SQL database provides greater flexibility since the queries will be run in response to each DHCP packet rather than requiring the server to be restarted.
DHCP reply options for devices (including network-specific options) can be fetched from SQL (or other data stores such as LDAP or redis) using an arbitrary lookup key. This can be performed multiple times as necessary using different contexts, for example to first set subnet-specific options and then to set group-specific options.
There is no set way to perform this but one method would be to create an SQL table such as
CREATE TABLE dhcpoptions (
context VARCHAR(30) NOT NULL,
identifier VARCHAR(255) NOT NULL,
option VARCHAR(511) NOT NULL,
);
Then populate "dhcpoptions" with reply options for a given identifier (e.g. MAC Address):
| context | identifier | option |
|---|---|---|
|
|
|
|
|
|
Additionally records can be added to map identifiers to a group of options that can be shared:
| context | identifier | option |
|---|---|---|
|
|
|
And then group reply options can be added to the "dhcpoptions" table:
| context | identifier | option |
|---|---|---|
|
|
|
|
|
|
|
|
|
Within the context of assigning options directly to devices, as well as to manually-curated groups of devices keyed by their MAC address:
-
Place device-specific options in the "dhcpoptions" table, with the
optioncolumn having the option name prefixed withreply.. -
Place entries in the "dhcpoptions" which set the
control.Group-Nameattribute to assign the device to one or more groups. -
Place the grouped options in the "dhcpoptions" table with the context being
by-group.
The following unlang will then allow retrieval of options from the database
%map(%sql("SELECT option FROM dhcpoptions WHERE context = 'by-mac' AND identifier = '%{Client-Hardware-Address}'"))
foreach dhcpgroup (control.Group-Name[*]) {
%map(%sql("SELECT option FROM dhcpoptions WHERE context = 'by-group' AND identifier = '%{dhcpgroup}'"))
}
In the above, the DHCP reply options would be assigned to a device with MAC address 02:01:aa:bb:cc:dd as follows:
-
Firstly, the
Log-Serveroption would be set to192.0.2.10and theLPR-Serveroption set to192.0.2.11. -
The
Group-Nameoption in thecontrollist gets set tosalesdept. -
Finally, the options for the
salesdeptgroup are now merged, setting aNTP-Serversoption to192.0.2.20, appending an additionalLog-Serveroption set to192.0.2.21, and prepending an additionalLPR-Serveroption set to192.0.2.22.
If instead you wanted to perform a "subclass" lookup based on the first three octets of the device’s MAC address then with tables containing the following sample data you could invoke an SQL lookup as shown:
| context | identifier | option |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
%map(%sql("SELECT option FROM dhcpoptions WHERE context = 'class-vendor' AND identifier = '%substring(%{Client-Hardware-Address}, 0, 6)'"))
foreach dhcpgroup (control.Group-Name[*]) {
%map(%sql("SELECT option FROM dhcpoptions WHERE context = 'by-group' AND identifier = '%{dhcpgroup}'"))
}
This is just one approach which can be taken to populate DHCP reply options from an SQL database.
Test "device", "class" and "group" options
You should now test that any device-related options that you have configured using the various methods available are applied successfully by generating packets containing those parameters based upon which the reply options are set.
For example, to test the iPXE user class example above you might want to generate a request as follows:
cat <<EOF > dhcp-packet-ipxe-boot.txt
Message-Type := Discover
Client-Hardware-Address := 02:01:aa:bb:cc:dd
User-Class := "iPXE-class-abc"
EOF
To which you would expect to see a response such as:
dhcpclient: ... ---------------------------------------------------------------------- Waiting for DHCP replies for: 5.000000 ---------------------------------------------------------------------- ... Message-Type = ::Offer Your-IP-Address = 1.2.3.4 Boot-Filename := "http://my.web.server/boot_script.php" ...