Add new howto pages.
Read this FAQ before posting questions to the mailing lists as your question may be answered.
-
== FreeRADIUS Overview
FreeRADIUS is the worlds leading RADIUS server used by Internet Service Providers (ISPs), cellular providers, and corporate and educational networks. RADIUS, which stands for “Remote Authentication Dial In User Service”, is a network protocol used to manage network access using xref:concepts:authproto.adoc[Authentication, Authorization and Accounting] processes.
FreeRADIUS is developed by a group of people who call themselves "The FreeRADIUS Project" and is sponsored by https://www.inkbridgenetworks.com/[InkBridge Networks].
-
=== What is FreeRADIUS and what is it supposed to do?
The FreeRADIUS Server is a daemon for unix and unix like operating systems which allows one to set up a radius protocol server. The RADIUS protocol manages the communication between network devices to facilitate remote user
* Authorizes those users or devices for specific network services.
* Accounts for and tracks the usage of those services.
-
=== How does FreeRADIUS differ from other radius servers?
FreeRADIUS is an open-source product with all the benefits of open-source software that includes flexibility, scalibility, and cost-effectivness. FreeRADIUS has many features not found in other free and commercial versions. Some of these features are:
* Exec-Program-Wait capability that allows an external program to execute after authentication and output a list of A/V pairs, which is then added to the reply.
* Supports PAM.
-
=== Can I install FreeRADIUS on any platform?
Yes. FreeRADIUS is compatible with all known equipment and products which implement the RADIUS standards. FreeRADIUS runs on a large number of 32 and 64 bit Unix-like platforms. Where there are compatibility issues is ofent due to third-party vendors' implementation of the relevant standards.
-
=== Can I get binary packages of FreeRADIUS?
Yes. You can find it on the official http://www.freeradius.org/[FreeRADIUS] site.
-
=== Can I build and install FreeRADIUS from source?
Yes. The source is available at ftp://ftp.freeradius.org/pub/radius/[ftp] or on https://github.com/FreeRADIUS/freeradius-server[github]. See the xref:howto:installation/source.adoc[instructions] on how to build FreeRADIUS.
-
=== Does FreeRADIUS Support IPv6?
Yes. FreeRADIUS v2 and later has full support for both IPv6 attributes and IPv6 network packets.
-
=== Can I get more information?
-Yes. The official site for http://www.freeradius.org/[FreeRADIUS] contains the server, documentation, and additional RADIUS programs.
-
-The mailto:freeradius-announce@lists.freeradius.org[freeradius-announce], mailto:freeradius-users@lists.freeradius.org[freeradius-users], and mailto:freeradius-devel@lists.freeradius.org[freeradius-devel] mailing lists are available for you to subscribe to.
-
-FreeRADIUS is supported by the https://www.inkbridgenetworks.com/[InkBridge Networks] team.
+Yes. The official site for http://www.freeradius.org/[FreeRADIUS] contains the server, documentation, and additional RADIUS programs. FreeRADIUS is supported by the https://www.inkbridgenetworks.com/[InkBridge Networks] team.
+include::partial$mailinglist.adoc[]
== User Management
-
=== Can I disconnect a user with FreeRADIUS?
No. A user with an active session can't be disconnected with FreeRADIUS. The RADIUS server doesn't actively maintain the user sessions and only receives information about these sessions from the NAS. This means that you have to signal your NAS to disconnect sessions. Depending on the NAS type and it's configuration, there are a number of ways to disconnect sessions.
-
-.Packet of Disconnect
+.Packet of disconnect
[%collapsible]
====
Packet of Disconnect is the standard and recommended method to disconnect users. It is supported by many newer NAS and uses a RADIUS packet (usually sent to port 3799 although some NAS use 1700 (Mikrotik for example)) to signal that a NAS should terminate an active session.
====
-
.SNMP
[%collapsible]
====
Many NAS support SNMP which can usually (among other things) be used to disconnect users, however implimentation details vary. Read your NAS documentation to find out whether it supports this, and which MIB to use.
====
-
.Radkill
[%collapsible]
====
Download the ftp://ftp.nmo.net/pub/radkill/radkill-latest.tar.gz[radkill] source archive and install the program on your server.
====
-
=== Can I send a message to PPP users?
Yes. RADIUS defines a Reply-Message attribute, which you can use to
However, Microsoft windows users can't see PPP messages due to Microsoft's implementation of the PPP protocol. For macs, the only dialer that shows up the server's message is http://www.rockstar.com[FreePPP].
-
=== Can I use Login-Time for groups instead of users?
Yes. There are several methods to manage login time for groups.
|DEFAULT Group == "weekends", Login-Time := "Sa-Su0800-2000"
|===
-
=== Can I permit access to any user regardless of password?
Yes. Edit the raddb/users file with the following entry on the first line (top of the file). This entry accepts everybody on to the network.
If you want this to apply to a single user replace DEFAULT with username. You can also add Auth-Type Accept to radcheck or radgroupcheck entries in order to accept that user/group. This only works for PAP, and does NOT work for EAP-TLS, CHAP, MSCHAP, or WIMAX authentication.
-
== Server Configuration
-
=== Is there a way to bind FreeRADIUS to a specific IP address?
Yes. There are several ways to bind the IP address.
No. The RADIUS server only logs the messages which a NAS sends to it. If your NAS is not sending those messages or attributes, then the RADIUS server will not log them. Configure your NAS to send the information you want to the RADIUS server. Once the NAS is sending the information, the server can then log it.
-
=== Do I need to use the Attribute Operators?
Yes. All of the attribute operators such as `:=`, `==`, `+=`, etc. are documented via the:
* xref:reference:raddb/mods-config/files/users.adoc[users] file,
-* xref:reference:unlang/condition/index.adoc[conditional expressions],
-* xref:reference:unlang/edit.adoc[attribute editing]
+* xref:reference:unlang/condition/index.adoc[conditional expressions],
+* xref:reference:unlang/edit.adoc[attribute editing].
-Note that the xref:reference:unlang/update.adoc[update] is no longer necessary. The new xref:reference:unlang/edit.adoc[attribute editing] is much simpler, and is more powerful.
+[NOTE]
+===
+The xref:reference:unlang/update.adoc[update] is no longer necessary. The new xref:reference:unlang/edit.adoc[attribute editing] is much simpler, and is more powerful.
+===
=== Can I send multiple values for an attribute ?
0x0010: 302e 302e 302e 3020 3130
====
-
=== Isn't CHAP more secure?
No. If CHAP is implemented as the authentication protocol, a file resides on your network with cleartext passwords for all the users that log on using FreeRADIUS. This is a limitation of the CHAP protocol itself, not the RADIUS protocol. The CHAP protocol **requires** that you store the passwords in plain-text format.
|passwords going cleartext over the phone line between the user and the terminal server.
|===
-
=== Can I limit access to only POP3 and SMTP?
Yes. The most common approach is to just assign non-globally-routable IP addresses to those users, such as https://datatracker.ietf.org/doc/html/rfc1918[RFC 1918] addresses. Make sure you have RADIUS authorization enabled on your NAS.
Depending on your internal network configuration, you may need to set up internal routes for those addresses, and if you don't want them to do anything besides SMTP and POP3 within your network, you'll have to set up ACLs on your dialup interfaces allowing only ports 25 and 110 through.
-
-.User entry in raddb/users file example:
+User entry in raddb/users file example
[%collapsible]
====
Fall-Through = Yes
====
-.CISCO configuation example:
+.CISCO configuation example
[%collapsible]
====
aaa authorization network default radius
The access list 160 gets applied on inbound packets and 161 on outbound packets.
====
-
=== Can I use Privledged Access Management (PAM) with FreeRADIUS?
Yes. Retrieve the redhat/radiusd.pam file from the distribution and save it as a new file in /etc/pam.d/radiusd.
With this method, I have NO users on /etc/password and NO need for lots of lines on /etc/raddb/users. time to search for a db enabled pam_listfile module
-
=== Is the RADIUS server broken after an upgrade?
No. After upgrading to FreeRADIUS, some users are unable to fully use the network, but their access worked with the previous RADIUS server you were using.
## What Email list do I use?
-There are several mailing lists associated with the FreeRADIUS server project. The lists are on the http://freeradius.org/list/[freeRADIUS] website. The current lists are:
-
-* *mailto:freeradius-users@lists.freeradius.org[freeradius-users]*
-This list is for all users of FreeRADIUS and deals with general questions related to FreeRADIUS
-* *mailto:freeradius-devel@lists.freeradius.org[freeradius-devel]*
-This list is for developers who are writing code for FreeRADIUS.The content is highly technical and is
-not suited to the average user.
-* *mailto:freeradius-announce@lists.freeradius.org[freeradius-announce]*
-This list is for all users of FreeRADIUS. Announcements about FreeRADIUS, including new versions
-and security issues, are made here.
+There are several mailing lists associated with the FreeRADIUS server project. The lists are on the http://freeradius.org/list/[freeRADIUS] website.
+
+include::partial$mailinglist.adoc[]
## How can I get training for my staff?
contains the most current packages for all common OS platforms for the
latest FreeRADIUS release.
-FreeRADIUS can also be installed from the source code. Please see the
- xref:howto:installation/index.adoc[installation guide] for instructions.
-
== Get the Source
This page describes how to perform the initial install and
= Introduction
-This is the FreeRADIUS version 4 documentation that is available under
+This FreeRADIUS version 4 documentation is available under
the Creative Commons Non-Commercial xref:LICENSE[license].
[WARNING]
The configuration may change. The behavior may change. The
documentation may change.
-Please wait for an official release before using version 4.
+Please wait for an official release before using version 4 (v4).
====
FreeRADIUS is a complex piece of software with many configuration
infinite configurations. The question for an administrator, then, is
what piece of the configuration to change, and how to change it.
-This documentation answers your basic and advanced questions about
+This updated documentation answers your basic and advanced questions about
functionality, configuration, and other scenarios. The FreeRADIUS team
-has updated the documentation for this major release. Everything in
-the server is fully documented with examples, developer information,
-and additional resources to help you.
+included examples, developer information,
+and extra resources to assist you.
-This documentation is divided into sections by subject area and organized by
+The documentation is organized into main sections, sub-sections with smaller pages, and links to pertinent information. This hierarchy ensures that
+you can find information easily and extract the instructions you need. For example, all the Howto guides are a series of small steps to guide you through a task. The main sections by subject area and organized by
task-based results as follows:
-* xref:getstarted.adoc[Getting Started] guide and FAQ to help you get setup in record time.
-* xref:concepts:index.adoc[Concepts] and overview provides a high level explanation for newcomers.
-* xref:reference:index.adoc[Reference] documentation includes the xref:reference:unlang/index.adoc[Unlang] syntax and xref:reference:raddb/index.adoc[Configuration Files].
-* xref:howto:index.adoc[Howto] guides step you through various tasks and includes xref:howto:installation/index.adoc[Installing] and xref:howto:installation/upgrade.adoc[Upgrade] guide.
-* xref:tutorials:new_user.adoc[Tutorials] task based learning with real-world configurations and debugging exercises.
-* xref:developers:index.adoc[Developers] section outlines coding standards, raising bugs, and contributing with GitHub.
-* xref:trouble-shooting/index.adoc[Troubleshooting] section to help you resolve the most common issues with FreeRADIUS installations and configurations.
+* xref:getstarted.adoc[Getting Started] helps you install the server, along with a xref:faq.adoc[FAQ] to answer your questions, and xref:trouble-shooting/index.adoc[Troubleshooting] tips to resolve any issues.
+* xref:concepts:index.adoc[Concepts] provides a high level explanation for newcomers and additional RADIUS xref:concepts:resources.adoc[Resources] for further reading.
+* xref:reference:index.adoc[Reference Documentation] details the xref:reference:unlang/index.adoc[Unlang] syntax and xref:reference:raddb/index.adoc[Configuration Files].
+* xref:howto:index.adoc[Howto] gives step-by-step instructions and includes xref:howto:installation/index.adoc[Installing] and xref:howto:installation/upgrade.adoc[Upgrading] guides.
+* xref:tutorials:new_user.adoc[Tutorials] explain real-world configurations through setups, debugging, and exercises.
+* xref:developers:index.adoc[Developers] outlines coding standards, raising defects, and using GitHub.
-Within each section, the documentation is organized into subsections,
-smaller pages, and relavent cross-links. This hierarchy ensures that
-you can find information quickly and extract the instructions you
-need. For example, the Howto guides are split into a series of small
-steps, each of which can be performed quickly.
+== What's new in FreeRADIUS v4
-
-== What's new in FreeRADIUS version 4
-
-FreeRADIUS version 4 is in "alpha" right now. If version 4 works,
+FreeRADIUS v4 is in "alpha" right now. If FreeRADIUS v4 works,
continue to use. If you have issues, *return* to using FreeRADIUS
-version 3.
+v3.
As of the time of this release, FreeRADIUS:
-* Abililty to proxy one packet to multiple destinations.
+* Has the abililty to proxy one packet to several destinations.
* Can capture a `failed` proxy, and fall back to local
authentication.
-* The server supports multiple clients with different shared
+* Server supports many clients with different shared
secrets behind one NAT gateway.
-* DHCP and VMPS are integrated with full functionality and features.
-* The server supports TACACS+.
+* DHCP and VMPS integrated with full functionality and features.
+* Server supports TACACS+.
* Connections to databases are `asynchronous` ensuring stable access,
and prevents server lockups.
* Enums are prefixed with `::`, as in `Service-Type == ::Framed-User`.
- * The server still does not always require (or print) the `::` prefix. That will change.
- * By implementing `::` for enums, the requirement to use `&` as a prefix for attribute names is not needed.
- * This change may require changes to all of the configuration. We will try to allow `&` or not, but that may not be possible.
+ ** The server still doesn't always require (or print) the `::` prefix. That will change.
+ ** By implementing `::` for enums, the requirement to use `&` as a prefix for attribute names is not needed.
+ ** This change may require an update to all of the configuration. We will try to allow `&`, but that may not be possible.
* Dynamic expansions have changed from `%{md5:foo}` to a more standard syntax of `%md5(foo)`.
- * The new syntax supports multiple comma-separated arguments such as `%function(a, b, c)`.
- * Expansions such as `%{User-Name}` still work in addition to expressions like `%{1+2}` too.
- * Alternation `%{%{foo}:-%{bar}}` has been replaced by `%{&foo || &bar}`, which is clearer and uses less nesting.
-* Python and Lua modules *only* partially fully support the v4 "nested" attributes.
-* RADIUS/TLS (RadSec) is not implemented.
-* TEAP and EAP-FAST are not implemented.
-* the "haproxy" and "reverse CoA' features are not implemented.
-
-Administrators using version 3 and wish to upgrade to version 4
-must read the xref:howto:installation/upgrade.adoc[Upgrading] page.
-This section explains the differences between the two versions and
-how an existing configuration can be reproduced in the latest
-release. Do *not* use version 3 configuration files with version 4. These configuration files are *not* compatible on a major version upgrade.
+ ** The new syntax supports multiple comma-separated arguments such as `%function(a, b, c)`.
+ ** Expansions such as `%{User-Name}` work in addition to expressions like `%{1+2}` too.
+ ** Alternation `%{&foo || &bar}` supersedes `%{%{foo}:-%{bar}}` now.
+* Python and Lua modules *only* partially support the v4 "nested" attributes.
+* RADIUS/TLS (RadSec) isn't available.
+* The "haproxy" and "reverse CoA" features aren't implemented.
+
+Administrators using version 3 that wish to upgrade to version 4
+must read the xref:howto:installation/upgrade.adoc[upgrading] guide.
+This guide explains the differences between the two versions and
+how an existing configuration is reproduced in the latest
+release. Do *not* use version 3 configuration files with version 4. These configuration files are *not* compatible on this major version upgrade.
[WARNING]
====
-Do not open bug reports about the previously listed features as missing.
-All such bug reports will be closed without comment.
+*Don't* open bug reports about previous features as missing. All such bug reports will be closed without comment.
-*Don't* create 4.0.0-alpha packages for your operating systems or Linux distributions. Our experience has been that creating "alpha" packages results in upset users that install that package. The users believed that the package is stable and then they will run into issues.
+*Don't* create 4.0.0-alpha packages for your operating systems or Linux distributions. Creating "alpha" packages results in upset users that install that package. The users believed that the package is stable and they run into issues.
====
-
== Network Requirements
-blah blah
+A RADIUS server requires a network connection with access to UDP ports 1812 for authentication and 1813 for the accounting traffic. These ports must be reachable by network devices like access points or VPN gateways that send authentication requests to the server. All network devices are configured with the appropriate IP address and network settings to facilitate communication with clients on the network.
=== Operating Systems
-The FreeRADIUS protocol works on all Unix based systems. It does not
+The FreeRADIUS protocol works on all Unix based systems. FreeRADIUS doesn't
run natively under Windows.
-
=== CPU/RAM/disk space requirements
-A FreeRADIUS server has minimal requirements. A basic FreeRADIUS installation uses 8 megabytes of RAM, under one hundred megabytes of disk space, and minimal CPU power. An Internet Service Provider with 10,000 or fewer users will not have any problems with any commodity system available at the time of this printing. If the ISP has more than 10,000 users, the overall system design becomes much more important than the specifications of an individual server.
-
-If the ISP has more than 10,000 users, the overall system design
-becomes much more important than the specifications of an individual
-server.
-
+A FreeRADIUS server has minimal requirements. A FreeRADIUS installation uses 8 MB of RAM, less than 100 MB of disk space, and minimal CPU power. An Internet Service Provider (ISP) with less than 10,000 users have no issues with a basic setup. ISPs with more than 10,000 users, focuses on system design such as more servers and databases.
=== Datastores
-The server can read or write to any database and both LDAP and SQL can be used in the same configuration simotaneously. The database queries are customizable and can adapt to any custom schema used at a customers site. The server supports fail-over and load balancing across multiple databases. There are no pre-set limits to the number, or type, of databases used.
+The server reads or writes to any database and both LDAP and SQL can be in the same configuration simultaneously. The database queries are customizable and can be adapted to any custom schema . The server supports fail-over and load balancing across multiple databases. There are no pre-set limits to the number, or type, of databases used.
== Debugging
-If you have ANY issues with your server, then restart the server
+If you have *any* issues with your server, then restart the server
in xref:radiusd_x.adoc[Debugging] mode. Review the logs to determine what
-the root problem is and make changes accordingly. Do only *ONE* change
+the root cause is and make changes. Do only *one* change
at a time and restart your server.
-
== More Information
-Many resources, https://www.inkbridge.io/[experts], and documentation sets are available to help you with your RADIUS server. Refer to xref:gethelp.adoc[Getting Help] for more details.
+The https://www.inkbridge.io/[RADIUS experts] are available to help you with your FreeRADIUS. See xref:gethelp.adoc[Getting Help] for more information and details.
// Copyright (C) 2025 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
// This documentation was developed by Network RADIUS SAS.
$ radiusd -X 2>&1 | tee debugfile
The server prints out the version number, copyright, and license information:
-
+[%collapsible]
+====
FreeRADIUS Version 3.0.17
Copyright (C) 1999-2017 The FreeRADIUS server project and contributors
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
You may redistribute copies of FreeRADIUS under the terms of the
GNU General Public License
For more information about these matters, see the file named COPYRIGHT
+====
Next, it prints out messages relating to debuggers (e.g. gdb). These messages are intended for developers, and can generally be ignored by everyone else.
Starting - reading configuration files ...
It then reads the dictionaries. It does not print out the name of every dictionary file it reads, as there are over 100 files, but they are never the less still loaded.
-
+[%collapsible]
+====
including dictionary file /usr/share/freeradius/dictionary
including dictionary file /usr/share/freeradius/dictionary.dhcp
including dictionary file /usr/share/freeradius/dictionary.vqp
including dictionary file /etc/raddb/dictionary
+====
Next is loads the main `radiusd.conf` file, and some associated ones like `proxy.conf` and `clients.conf`
-
+[%collapsible]
+====
including configuration file /etc/raddb/radiusd.conf
including configuration file /etc/raddb/proxy.conf
including configuration file /etc/raddb/clients.conf
+====
It now loads all of the modules. The module configuration is usually stored in `raddb/mods-enabled/`, with one module configuration per file in that directory.
Sometimes the module you're using does not seem to be loaded or used. In that case, you should check this section to see that the file is loaded.
-
+[%collapsible]
+====
including files in directory /etc/raddb/mods-enabled/
including configuration file /etc/raddb/mods-enabled/pap
including configuration file /etc/raddb/mods-enabled/expiration
including configuration file /etc/raddb/mods-enabled/realm
including configuration file /etc/raddb/mods-enabled/cache_eap
including configuration file /etc/raddb/mods-enabled/replicate
+====
Next, some policies are loaded. These policies are ones which the server uses (for example) to canonicalize user names, and to do things like attribute re-writes, sanity checks, etc.
-
+[%collapsible]
+====
including files in directory /etc/raddb/policy.d/
including configuration file /etc/raddb/policy.d/control
including configuration file /etc/raddb/policy.d/cui
including files in directory /etc/raddb/sites-enabled/
including configuration file /etc/raddb/sites-enabled/default
including configuration file /etc/raddb/sites-enabled/inner-tunnel
+====
### Server Configuration
The result is that if you set a configuration item, *it will be printed out in the debug output*. You should verify that this is the case, especially if it looks like the server is not using the setting you edited. If the configuration item does not appear in the debug output, *then the server is not using it.*
This is the "main" server configuration:
-
+[%collapsible]
+====
main {
name = "radiusd"
run_dir = "/var/run/radiusd"
libdir = "/usr/lib"
radacctdir = "/var/log/radius/radacct"
+====
Next we have some generic configuration settings which don't belong anywhere else.
-
+[%collapsible]
+====
hostname_lookups = no
max_request_time = 30
cleanup_delay = 5
checkrad = "/sbin/checkrad"
debug_level = 0
proxy_requests = yes
+====
And the logging configuration.
-
+[%collapsible]
+====
log {
stripped_names = no
auth = no
}
resources {
}
+====
The security settings.
-
+[%collapsible]
+====
security {
max_attributes = 200
reject_delay = 1.000000
allow_vulnerable_openssl = "yes"
}
}
+====
At this point, the server is well on it's way to running.
radiusd: #### Loading Realms and Home Servers ####
The over all proxy configuration is loaded.
-
+[%collapsible]
+====
proxy server {
retry_delay = 5
retry_count = 3
dead_time = 120
wake_all_if_all_dead = no
}
+====
Followed by `home_server` configurations.
-
+[%collapsible]
+====
home_server localhost {
ipaddr = 127.0.0.1
port = 1812
mrd = 30
}
}
+====
Followed by `home_server_pool` configurations.
-
+[%collapsible]
+====
home_server_pool my_auth_failover {
type = fail-over
home_server = localhost
}
+====
Followed by `realm` configurations.
-
+[%collapsible]
+====
realm example.com {
auth_pool = my_auth_failover
}
realm int {
virtual_server = inner-tunnel
}
+====
### Clients
It now loads individual clients:
-
+[%collapsible]
+====
radiusd: #### Loading Clients ####
client localhost {
ipaddr = 127.0.0.1
idle_timeout = 30
}
}
+====
### Auth-Type
The server then creates `Auth-Type`, as set in the virtual servers. These `Auth-Type` names and values are used by the modules, so they need to be created now.
-
+[%collapsible]
+====
# Creating Auth-Type = mschap
# Creating Auth-Type = digest
# Creating Auth-Type = eap
# Creating Auth-Type = PAP
# Creating Auth-Type = CHAP
# Creating Auth-Type = MS-CHAP
+====
### Modules
When you are editing a module configuration, it is good to check the debug output for that module, to see:
-* was the module loaded?
-* is it using the file you edited?
-* are the configuration changes you made showing up in the debug output?
+* Was the module loaded?
+* Is it using the file you edited?
+* Are the configuration changes you made showing up in the debug output?
Some modules like `expiration` do not have any configuration items, and therefore don't print out any configuration when they are loaded.
# Loading module "expiration" from file /etc/raddb/mods-enabled/expiration
This module loads the `users` file.
-
+[%collapsible]
+====
# Loaded module rlm_files
# Loading module "files" from file /etc/raddb/mods-enabled/files
files {
acctusersfile = "/etc/raddb/mods-config/files/accounting"
preproxy_usersfile = "/etc/raddb/mods-config/files/pre-proxy"
}
+====
The server loads a large number of modules, so we will omit them here.
server default { # from file /etc/raddb/sites-enabled/default
It then double-checks the various processing sections.
-
+[%collapsible]
+====
# Loading authenticate {...}
# Loading authorize {...}
# Loading preacct {...}
# Loading accounting {...}
+====
The `sql` module is in the default configuration, even if the `sql` module is not enabled. This warning message is then printed out.
It can be ignored, or, in a production environment where you don't use `sql`, you can just remove references to `sql` from the virtual servers.
-
+[%collapsible]
+====
Ignoring "sql" (see raddb/mods-available/README.rst)
# Loading post-proxy {...}
# Loading post-auth {...}
# Loading authorize {...}
# Loading session {...}
# Loading post-auth {...}
+====
In some situations, it tells you where the configuration can be simplified.
radiusd: #### Opening IP addresses and Ports ####
First, it prints out the configuration for the listen sections.
-
+[%collapsible]
+====
listen {
type = "auth"
ipaddr = *
ipaddr = 127.0.0.1
port = 18120
}
+====
After reading all of the configuration, it opens the ports, and prints out a list of IP addresses and ports which it is using.
-
+[%collapsible]
+====
Listening on auth address * port 1812 bound to server default
Listening on acct address * port 1813 bound to server default
Listening on auth address :: port 1812 bound to server default
Listening on auth address 127.0.0.1 port 18120 bound to server inner-tunnel
Listening on proxy address * port 39556
Listening on proxy address :: port 52609
+====
And we finally get to this line.
(0) Received Access-Request Id 104 from 127.0.0.1:33278 to 127.0.0.1:1812 length 73
After that, it prints out all of the attributes which were received in the packet.
-
+[%collapsible]
+====
(0) User-Name = "bob"
(0) User-Password = "wrongpassword"
(0) NAS-IP-Address = 127.0.1.1
(0) NAS-Port = 0
(0) Message-Authenticator = 0x3d27116b37323e4f629b4e8217fc25c8
+====
-Note that if an attribute is not printed here, then *it does not exist*. If you need the packet to contain an attribute, then you must **fix the NAS** so that the NAS sends the attribute.
+[NOTE]
+====
+If an attribute is not printed here, then *it does not exist*. If you need the packet to contain an attribute, then you must **provision the NAS** so that the NAS sends the attribute.
+====
Once the packet is received, it is run through the various processing sections of the server. For Access-Request packets, these are `authorize`, `authenticate`, and `post-auth`.
The `authorize` section contains a number of modules, along with unlang keywords like `if`, `update`, etc.
Each module prints out what it is doing, and why. For example, the `suffix` module here is looking for `User-Name` attributes which contain `user@domain`.
-
+[%collapsible]
+====
(0) suffix: Checking for suffix after "@"
(0) suffix: No '@' in User-Name = "bob", looking up realm NULL
(0) suffix: No such realm "NULL"
+====
The server core then prints out the "return code" of the module. See `man unlang` for a deeper explanation of return codes.
(0) Failed to authenticate the user
The packet is processed through the `Post-Auth-Type REJECT` section
-
+[%collapsible]
+====
(0) Using Post-Auth-Type Reject
(0) # Executing group from file /etc/raddb/sites-enabled/default
(0) Post-Auth-Type REJECT {
+====
That section contains more modules and unlang statements.
Here, the `attr_filter` module is removing attributes which are forbidden from appearing in an Access-Reject packet.
-
+[%collapsible]
+====
(0) attr_filter.access_reject: EXPAND %{User-Name}
(0) attr_filter.access_reject: --> bob
(0) attr_filter.access_reject: Matched entry DEFAULT at line 11
(0) [noop] = noop
(0) } # else = noop
(0) } # policy remove_reply_message_if_eap = noop
+====
Finally, the `Post-Auth-Type REJECT` section is done.
If there are any attributes in the reply packet, they will be printed here. In this case, there are none.
-Note that you **should** check the reply attributes to see if the server is sending the reply you expect. If it is not sending the correct reply. you will need to fix the configuration to do so.
+[NOTE]
+====
+You **must** check the reply attributes to see if the server is sending the reply you expect. If it is not sending the correct reply. you will need to fix the configuration to do so.
+====
If it is sending the correct reply, but the user is not getting the expected service, then the problem is the NAS. No amount of changing the server configuration will make the NAS behave.
Ready to process requests
The debug log has another packet, which we will skip, as it's largely the same as the previous one.
-
+[%collapsible]
+====
(1) Received Access-Request Id 146 from 127.0.0.1:40967 to 127.0.0.1:1812 length 73
(1) User-Name = "bob"
(1) User-Password = "wrongagain"
(1) NAS-IP-Address = 127.0.1.1
(1) NAS-Port = 0
+====
The debug log then shows a successful authentication.
The input packet is largely the same, but has a different `User-Name` and `User-Password` attribute.
-
+[%collapsible]
+====
(2) Received Access-Request Id 135 from 127.0.0.1:40344 to 127.0.0.1:1812 length 77
(2) User-Name = "bob@int"
(2) User-Password = "test"
(2) NAS-IP-Address = 127.0.1.1
(2) NAS-Port = 0
+====
The `Message-Authenticator` attribute is a cryptographic signature of the packet, and has no other meaning.
(2) suffix: Found realm "int"
The `suffix` module splits the `User-Name` into a `Stripped-User-Name` and `Realm` attributes. The `Stripped-User-Name` is used by subsequent modules to match the user's name.
-
+[%collapsible]
+====
(2) suffix: Adding Stripped-User-Name = "bob"
(2) suffix: Adding Realm = "int"
(2) suffix: Proxying request from user bob to realm int
(2) [files] = noop
(2) } # authorize = updated
(2) Starting proxy to home server (null) port 1812
+====
This configuration has been changed from the default configuration to proxy packets to the `inner-tunnel` virtual server. This change was done here strictly for demonstration purposes. It is not necessary (and you should not do it!) in normal configurations.
(2) } # authorize = updated
It now runs `Auth-Type PAP`
-
+[%collapsible]
+====
(2) Found Auth-Type = PAP
(2) # Executing group from file /etc/raddb/sites-enabled/inner-tunnel
(2) Auth-Type PAP {
+====
The `pap` module tells you that everything is OK.
-
+[%collapsible]
+====
(2) pap: Login attempt with password
(2) pap: Comparing with "known good" Cleartext-Password
(2) pap: User authenticated successfully
(2) [pap] = ok
(2) } # Auth-Type PAP = ok
+====
It now runs the normal `post-auth` section
-
+[%collapsible]
+====
(2) # Executing section post-auth from file /etc/raddb/sites-enabled/inner-tunnel
(2) post-auth {
(2) update reply {
(2) } # post-auth = noop
(2) Finished internally proxied request.
(2) Clearing existing &reply: attributes
+====
Because this is a proxied request, it now runs the `post-proxy` section of the `default` virtual server.
-
+[%collapsible]
+====
(2) # Executing section post-proxy from file /etc/raddb/sites-enabled/default
(2) post-proxy {
(2) policy debug_reply {
(2) } # if ("%{debug_attr:reply:}" == '') = noop
(2) } # policy debug_reply = noop
(2) } # post-proxy = noop
+====
This `Auth-Type = Accept` is added by the server code when proxying. Since the proxied request returned an Access-Accept, the `default` virtual server treats that as a successful authentication.
(2) Auth-Type = Accept, accepting the user
It then runs the `post-auth` section from the `default` virtual server.
-
+[%collapsible]
+====
(2) # Executing section post-auth from file /etc/raddb/sites-enabled/default
(2) post-auth {
(2) update {
(2) } # else = noop
(2) } # policy remove_reply_message_if_eap = noop
(2) } # post-auth = noop
+====
And finally returns an Access-Accept to the client. The `Reply-Message` here was take from `line 1` of the `users` file, when it matched above.
-
+[%collapsible]
+====
(2) Sent Access-Accept Id 135 from 127.0.0.1:1812 to 127.0.0.1:40344 length 0
(2) Reply-Message := "hello"
(2) Finished request
(2) Cleaning up request packet ID 135 with timestamp +74
Ready to process requests
^C
+====
That is a *lot* of information to go through. We hope that this page has been useful.
* The debug output shows that the packets are being processed as you expect.
* The response packets contain the attributes you expect to see.
-
-
-== Best Practices
-Please see the description of FreeRADIUS mailing lists. For normal discussion of the server and how to use it, subscribe to the FreeRADIUS user-list. Only subscribe to the development list if you are interested in writing software for the new server.
-
-* *mailto:freeradius-users@lists.freeradius.org[freeradius-users]*
-This list is for all users of FreeRADIUS and deals with general questions related to FreeRADIUS.
-* *mailto:freeradius-devel@lists.freeradius.org[freeradius-devel]*
-This list is for developers who are writing code for FreeRADIUS. The content is highly technical and is not suited to the average user. If you looking to contribute code, please join this list.
-* *https://lists.freeradius.org/pipermail/freeradius-users/[User Mailing List Archive]*
-An archive of all previous posts and emails from the users' email list.
-* *https://lists.freeradius.org/pipermail/freeradius-devel/[Developer Mailing List Archive]*
-An archive of all previous posts and emails from the developement users' email list.
+Please see the following for a description of the FreeRADIUS mailing lists. For normal discussion of the server and how to use it, subscribe to the FreeRADIUS user-list. Only subscribe to the development list if you are interested in writing software for the new server.
+
+
+[cols="1,3"]
+|===
+|Mailing List|Description
+
+|mailto:freeradius-announce@lists.freeradius.org[freeradius-announce]
+|Announcements about FreeRADIUS, including new versions and security issues, are made here.
+
+|mailto:freeradius-users@lists.freeradius.org[freeradius-users]
+|This list is for all users of FreeRADIUS and deals with general questions related to FreeRADIUS.
+
+|mailto:freeradius-devel@lists.freeradius.org[freeradius-devel]
+|This list is for developers who are writing code for FreeRADIUS. The content is highly technical and is not suited to the average user. If you looking to contribute code, please join this list.
+
+|https://lists.freeradius.org/pipermail/freeradius-users/[User Mailing List Archive]
+|An archive of all previous posts and emails from the users' email list.
+
+|https://lists.freeradius.org/pipermail/freeradius-devel/[Developer Mailing List Archive]
+|An archive of all previous posts and emails from the developement users' email list.
+|===
=== Request Processing
When the server processes requests, it manages four
-xref:reference:unlang/list.adoc[attribute lists]:
+xref:reference:unlang/list.adoc[attribute lists].
-`request`:: attributes taken from the received packet
+.Attribute Lists and Details
-`reply`:: attributes which will be sent in the reply
+[cols="1,2"]
+|===
+|Attribute List|Description
-`control`:: attributes used to control how the server operates. These are never sent in a packet
+|`request`
+|Attributes taken from the received packet.
-`session-state`:: attributes which are saved and restroed across multiple request / reply exchanges.
+|`reply`
+|Attributes which will be sent in the reply.
+
+|`control`
+|Attributes used to control how the server operates. These are never sent in a packet.
+
+|`session-state`
+|Attributes which are saved and restored across multiple request / reply exchanges.
+|===
All of these lists are available to all modules. All of these lists are available in xref:reference:unlang/index.adoc[Unlang]
= Protocols
-
== RADIUS Protocol
-RADIUS is a protocol for remote user Authorization, Authentication, and Accounting. Its primary use is for Internet Service Providers, though it may as well be used on any network that needs a centralised authentication and/or accounting service for its workstations.
+RADIUS is a protocol for remote user Authorization, Authentication, and Accounting. Its primary use is for Internet Service Providers, though it may as well be used on any network that needs a centralized authentication and/or accounting service for its workstations.
RADIUS is often used in larger Wi-Fi (wireless) networks for authentication purposes, replacing the simple shared key methods which are uncomfortable if a Wi-Fi network reaches a specific size.
The protocol originally was designed by the well known terminal server manufacturer Livingston for use with their Portmaster series of terminal servers. Since then it has been implemented by hundreds other vendors and has a become an Internet Standard RFC. The DIAMETER protocol is the designated successor, but RADIUS is still commonly used today.
-
=== Radius Protocol dependencies
UDP: RADIUS uses UDP as its underlying protocol. The registered UDP port for RADIUS traffic is 1812; the early deployment of RADIUS used UDP port 1645, which conflicted with the "datametrics" service. When RADIUS is used for accounting rather than authentication and configuration, the registered UDP port is 1813; the early deployment used port 1646, which conflicted with the "sa-msg-port" service.
-
-== Authentication PROTOCOLS
+== Authentication Protocols
In order for RADIUS authentication to work, user passwords need to be stored in a format that is understood by the authentication protocol used by the client. Many protocols integrated with RADIUS include:
Authentication protocols used in RADIUS are not always compatible with the way the passwords have been stored. The following table shows which protocol is compatible with what kind of password.
-
=== Authentication Protocol and Password Compatibility
Passwords may be stored in a DB in many forms. Clear-text, MD5 hashed, crypt'd, NT hash, or other methods are all commonly used. Authentication protocols used in RADIUS are not always compatible with the way the passwords have been stored. The following table shows which protocol is compatible with what kind of password.
The password hashes, and authentication protocols were designed to be incompatible. If the cell in the above table is red, then it's impossible to make the authentication protocol use that form of the password. Your only choices are to stop trying to use that authentication protocol, or to store the passwords in a form compatible with that authentication protocol. The last choice often means asking all users to change their passwords, unfortunately.
-
== More Information
Refer to xref:reference:dictionary/index.adoc[Attributes] for more protocol attribute details and https://www.iana.org/assignments/radius-types/radius-types.xhtml[RADIUS Packet Types].
= Overview
-The server is written in a “plug in” model. The server core does the basic RADIUS and network handling.
-Almost everything else is managed as a plug-in module. This design is what enables the policy
-language to be incredibly exible. The policy language can simply run one or more plug-in modules, in any
+The server is written in a “plug in” model. The server core does the basic RADIUS and network handling. Almost everything else is managed as a plug-in module. This design is what enables the policy language to be incredibly exible. The policy language can simply run one or more plug-in modules, in any
order. Each plug-in module can be responsible for onelogical unit of functionality.
-For example, each of the authentication methods (PAP,CHAP, MS-CHAP, TOTP, and EAP) are individual plug-
-in modules. Similarly, each database connector (SQL,Redis, LDAP, etc.) are individual plug-in modules.
-In many cases, no code changes to the server core have to be made in order to support
-complex new functionality.
+For example, each of the authentication methods (PAP,CHAP, MS-CHAP, TOTP, and EAP) are individual plug-in modules. Similarly, each database connector (SQL,Redis, LDAP, etc.) are individual plug-in modules. In many cases, no code changes to the server core have to be made in order to support complex new functionality.
== What is RADIUS?
-RADIUS, which stands for “Remote Authentication Dial In User Service”, is a network protocol - a system
-that defines rules and conventions for communication between network devices - for remote user
-authentication and accounting. Commonly used by Internet Service Providers (ISPs), cellular network
+RADIUS, which stands for “Remote Authentication Dial In User Service”, is a network protocol that defines rules and conventions for communication between network devices for remote user authentication and accounting. Commonly used by Internet Service Providers (ISPs), cellular network
providers, and corporate and educational networks, the RADIUS protocol serves three primary functions:
-* Authenticates users or devices before allowing them access to a network
-* Authorizes those users or devices for specific network services
+* Authenticates users or devices before allowing them access to a network.
+* Authorizes those users or devices for specific network services.
* Accounts for and tracks the usage of those services.
=== History
-In 1991, Merit Network, a non-profit internet provider, required a creative way to manage dial-in access to
-various Points-Of-Presence (POPs) across its network. In response to this need, RADIUS was created by
-Livingston Enterprises.
-At the time RADIUS was created, network access systems were distributed across a wide area and were
-run by multiple independent organizations. Central administrators wanted to prevent problems with
-security and scalability, and thus did not want to distribute user names and passwords; instead, they
-wanted the remote access servers to contact a central server to authorize access to the requested system
-or service. In response to contact from the remote access server, the central server would return a
-“success” or “failure” message, and the remote machines would be in charge of enforcing this response
-for each end user.
-The goal of RADIUS was, therefore, to create a central location for user authentication, wherein users from
-many locations could request network access.
-The simplicity, efficiency, and usability of the RADIUS system led to its widespread adoption by network
-equipment vendors, to the extent that currently, RADIUS is considered an industry standard and is also
-positioned to become an Internet Engineering Task Force (IETF) standard.
+In 1991, Merit Network, a non-profit internet provider, required a creative way to manage dial-in access to various Points-Of-Presence (POPs) across its network. In response to this need, RADIUS was created by Livingston Enterprises.
+At the time RADIUS was created, network access systems were distributed across a wide area and were run by multiple independent organizations. Central administrators wanted to prevent problems with security and scalability, and thus did not want to distribute user names and passwords; instead, they
+wanted the remote access servers to contact a central server to authorize access to the requested system or service. In response to contact from the remote access server, the central server would return a
+“success” or “failure” message, and the remote machines would be in charge of enforcing this response for each end user.
+
+The goal of RADIUS was, therefore, to create a central location for user authentication, wherein users from many locations could request network access.
+The simplicity, efficiency, and usability of the RADIUS system led to its widespread adoption by network equipment vendors, to the extent that currently, RADIUS is considered an industry standard and is also positioned to become an Internet Engineering Task Force (IETF) standard.
=== Customers
-A wide and varied array of businesses currently utilize the RADIUS protocol for their authentication and
-accounting needs. Some examples of RADIUS customers are:
+A wide and varied array of businesses currently utilize the RADIUS protocol for their authentication and accounting needs. Some examples of RADIUS customers are:
-* Cellular network providers with millions of users
-* Small WISP start-up providing the local neighborhood with Internet connectivity
-* Enterprise networks implementing Network Access Control (NAC) using 802.1x to ring fence their
-network
+* Cellular network providers with millions of users.
+* Small WISP start-up providing the local neighborhood with Internet connectivity.
+* Enterprise networks implementing Network Access Control (NAC) using 802.1x to ring fence their network.
=== Benefits
-The RADIUS client server protocol contains many technological advantages for customers, including:
+The RADIUS client-server architecture provides an open and scalable solution that is broadly supported by a large vendor base. It can be readily modified to meet a variety of situations. Customers can modify RADIUS-based authentication servers to work with a large number of security systems on the market.
+RADIUS servers work with any communications device that supports the RADIUS client protocol. In addition, the flexibility of the RADIUS authentication mechanisms allows an organization to maintain any investment they may have made in an existing security technology: customers can modify the
+RADIUS server to run with any type of security technology. The flexible authentication mechanisms inherent in the RADIUS server facilitate its integration with existing and legacy systems when required.
-* An open and scalable solution
-* Broad support by a large vendor base
-* Easy modification
-* Separation of security and communication processes
-* Adaptable to most security systems
-* Workable with any communication device that supports RADIUS client protocol
-
-The RADIUS client-server architecture provides an open and scalable solution that is broadly supported
-by a large vendor base. It can be readily modified to meet a variety of situations. Customers can modify
-RADIUS-based authentication servers to work with a large number of security systems on the market.
-RADIUS servers work with any communications device that supports the RADIUS client protocol.
-In addition, the flexibility of the RADIUS authentication mechanisms allows an organization to maintain
-any investment they may have made in an existing security technology: customers can modify the
-RADIUS server to run with any type of security technology. The flexible authentication mechanisms
-inherent in the RADIUS server facilitate its integration with existing and legacy systems when required.
-
-Another advantage of the RADIUS architecture is that any component of a security system that supports
-the RADIUS protocols can derive authentication and authorization from the central RADIUS server.
+Another advantage of the RADIUS architecture is that any component of a security system that supports the RADIUS protocols can derive authentication and authorization from the central RADIUS server.
Alternatively, the central server can integrate with a separate authentication mechanism.
The utility of the RADIUS protocol extends beyond those systems that utilize network access devices and
terminal servers for network access. RADIUS has been widely accepted by Internet Service Providers (ISPs)
to provide Virtual Private Network (VPN) services. In this context, RADIUS technology allows an organization to use ISP infrastructure for communications securely.
+
The distributive nature of RADIUS effectively separates the security processes (carried out on the authentication server) from the communications processes (implemented by the modem pool or the Network
Access Server (NAS)), allowing for a single centralized information store for authorization and authentication information. This centralization can significantly lessen the administrative burden of providing
appropriate access control for a large number of remote users. If ensuring high availability is not a priority,
then redundancy is not required; this centralization can thus be maximized, since all RADIUS-compatible
hardware on a LAN can derive authentication services from a single server.
+In summary, the RADIUS client server protocol contains many technological advantages for customers, including:
+
+* An open and scalable solution
+* Broad support by a large vendor base
+* Easy modification
+* Separation of security and communication processes
+* Adaptable to most security systems
+* Workable with any communication device that supports RADIUS client protocol
+
== What is FreeRADIUS?
FreeRADIUS is the most popular and the most widely deployed open source RADIUS server in the world.
-It serves as the basis for multiple commercial offerings, and it supplies the authentication, authorization,
-and accounting (AAA) needs of many Fortune 500 companies and Tier 1 ISPs. It is also widely used by the
-academic community (i.e., eduroam, the world-wide roaming access service developed for the international research and education community, utilizes FreeRADIUS software).
-FreeRADIUS was started in August 1999 by Alan DeKok and Miquel van Smoorenburg. Miquel had
-previously written the Cistron RADIUS server software, which had been widely adopted when the
-Livingston server was no longer in service. FreeRADIUS was developed using a modular design, to
-encourage more active community involvement.
+It serves as the basis for multiple commercial offerings, and it supplies the authentication, authorization, and accounting (AAA) needs of many Fortune 500 companies and Tier 1 ISPs. It is also widely used by the academic community (i.e., eduroam, the world-wide roaming access service developed for the international research and education community, utilizes FreeRADIUS software).
+FreeRADIUS was started in August 1999 by Alan DeKok and Miquel van Smoorenburg. Miquel had previously written the Cistron RADIUS server software, which had been widely adopted when the Livingston server was no longer in service. FreeRADIUS was developed using a modular design, to encourage more active community involvement.
=== Features
-More authentication types are supported by FreeRADIUS than by any other open source server. For
-example, FreeRADIUS is the only open source RADIUS server to support Extensible Authentication
-Protocol (EAP).
-FreeRADIUS is also the only open source RADIUS server to support virtual servers. The use of virtual
-servers means that complex implementations are simplified and ongoing support and maintenance costs
-for network administrators are greatly reduced; thus, the ability of FreeRADIUS to support virtual servers
+More authentication types are supported by FreeRADIUS than by any other open source server. For example, FreeRADIUS is the only open source RADIUS server to support Extensible Authentication Protocol (EAP).
+FreeRADIUS is also the only open source RADIUS server to support virtual servers. The use of virtual servers means that complex implementations are simplified and ongoing support and maintenance costs for network administrators are greatly reduced; thus, the ability of FreeRADIUS to support virtual servers
gives it a huge advantage over the competition.
=== Modularity
-The modular design protocol makes FreeRADIUS easy to understand. The modular interface also
-simplifies adding or removing modules - for example, if a feature is not needed for a particular configuration, the module is easily removed. Once the module is removed, it does not affect server performance,
-memory use, or security. This flexibility enables the server to run on platforms ranging from embedded
-systems to multi-core machines with gigabytes of RAM.
+The modular design protocol makes FreeRADIUS easy to understand. The modular interface also simplifies adding or removing modules. For example, if a feature is not needed for a particular configuration, the module is easily removed. Once the module is removed, it does not affect server performance,
+memory use, or security. This flexibility enables the server to run on platforms ranging from embedded systems to multi-core machines with gigabytes of RAM.
=== Scalability
-A single RADIUS server can easily transition from handling one request every few seconds to handling
-thousands of requests per second, simply by reconfiguring a few default settings. Many large organizations (those with more than 10 million customers) are dependent on FreeRADIUS for their AAA needs.
+A single RADIUS server can easily transition from handling one request every few seconds to handling thousands of requests per second, simply by reconfiguring a few default settings. Many large organizations (those with more than 10 million customers) are dependent on FreeRADIUS for their AAA needs.
Often, only a single FreeRADIUS server is required to fill the needs of these large organizations.
-While many commercial severs offer different versions of their software to handle different needs, only
-the latest version of FreeRADIUS is needed to obtain better performance, more realms, more RADIUS
-clients, and many other features, with no need to purchase additional product licenses.
+While many commercial severs offer different versions of their software to handle different needs, only the latest version of FreeRADIUS is needed to obtain better performance, more realms, more RADIUS clients, and many other features, with no need to purchase additional product licenses.
== Features
* Complete support for https://datatracker.ietf.org/doc/html/rfc2865[RFC 2865] and https://datatracker.ietf.org/doc/html/rfc2866[RFC 2866] attributes.
-* Authentication Protocol supports for :
-** EAP or protocol/EAP with EAP-MD5, EAP-SIM, EAP-TLS, EAP-TTLS
-** EAP-PEAP or protocol/EAP-PEAP
-** Cisco LEAP or protocol/LEAP and EAP sub-types
+* Authentication Protocol supports for:
+** EAP or protocol/EAP with EAP-MD5, EAP-SIM, EAP-TLS, EAP-TTLS.
+** EAP-PEAP or protocol/EAP-PEAP.
+** Cisco LEAP or protocol/LEAP and EAP sub-types.
* Vendor Specific Attributes for over a hundred vendors including BinTec, Foundry, Cisco, Juniper, Lucent/Ascend, HP ProCurve, Microsoft, USR/3Com, Acc/Newbridge.
-* All known RADIUS Clients
-* Flexible configurations using attribute pairs
-* Supports virtual servers
+* All known RADIUS clients.
+* Flexible configurations using attribute pairs.
+* Supports virtual servers.
// Copyright (C) 2025 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
// This documentation was developed by Network RADIUS SAS.
= RADIUS
-RADIUS is a protocol for remote user Authorization, Authentication and Accounting. Its primary use is for Internet Service Providers, though it may as well be used on any network that needs a centralised authentication and/or accounting service for its workstations.
+RADIUS is a protocol for remote user Authorization, Authentication and Accounting. Its primary use is for Internet Service Providers, though it may as well be used on any network that needs a centralized authentication and/or accounting service for its workstations.
RADIUS is often used in larger Wi-Fi (wireless) networks for authentication purposes, replacing the simple shared key methods which are uncomfortable if a Wi-Fi network reaches a specific size.
= RESOURCES
-== Primary sites
+== Primary Sites
* *https://www.freeradius.org/[FreeRADIUS]*
* *https://www.inkbridgenetworks.com/[Inkbridge Networks]*
-== Mailing Lists
-
-Please see the description of FreeRADIUS mailing lists. For normal discussion of the server and how to use it, subscribe to the FreeRADIUS user-list. Only subscribe to the development list if you are interested in writing software for the new server.
-
-* *mailto:freeradius-users@lists.freeradius.org[freeradius-users]*
-This list is for all users of FreeRADIUS and deals with general questions related to FreeRADIUS.
-* *mailto:freeradius-devel@lists.freeradius.org[freeradius-devel]*
-This list is for developers who are writing code for FreeRADIUS. The content is highly technical and is not suited to the average user. If you looking to contribute code, please join this list.
-* *mailto:freeradius-announce@lists.freeradius.org[freeradius-announce]*
-This list is for all users of FreeRADIUS. Announcements about FreeRADIUS, including new versions and security issues, are made here.
-
-== Archive Mailing Lists
-* https://lists.freeradius.org/pipermail/freeradius-users/[User Mailing List Archive]
-* https://lists.freeradius.org/pipermail/freeradius-devel/[Developer Mailing List Archive]
-
== Mailing lists
include::ROOT:partial$mailinglist.adoc[]
* *https://www.iana.org/assignments/radius-types/radius-types.xhtml[RADIUS Packet Types]*
->>>>>>> 0e9c6571f1 (Updated faq, troubleshooting, added pages. Updated top-level nav file to include new entries.)
// Copyright (C) 2025 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
// This documentation was developed by Network RADIUS SAS.
*** xref:modules/krb5/index.adoc[Krb5]
*** xref:modules/ldap/index.adoc[LDAP]
-
**** xref:modules/ldap/bootstrap_openldap/index.adoc[Installing and Configuring OpenLDAP]
***** xref:modules/ldap/bootstrap_openldap/docker.adoc[Docker]
***** xref:modules/ldap/bootstrap_openldap/packages.adoc[Packages]
**** xref:modules/sqlippool/insert.adoc[Inserting IPs into SQL]
** xref:protocols/index.adoc[Protocols]
-
-** Operating System
+*** xref:protocols/dhcp/index.adoc[DHCP]
+**** xref:protocols/dhcp/prepare.adoc[Preparation]
+**** xref:protocols/dhcp/enable.adoc[Enabling the DHCP service]
+**** xref:protocols/dhcp/test.adoc[Testing the DHCP service]
+**** xref:protocols/dhcp/policy.adoc[Defining the DHCP policy]
+***** xref:protocols/dhcp/policy_ippool_creation.adoc[IP pool creation]
+***** xref:protocols/dhcp/policy_common_options.adoc[Common options]
+***** xref:protocols/dhcp/policy_network_options.adoc[Network options and IP pool selection]
+***** xref:protocols/dhcp/policy_subnet_options.adoc[Subnet options]
+***** xref:protocols/dhcp/policy_device_options.adoc[Device, class and group options]
+***** xref:protocols/dhcp/policy_ippool_access.adoc[IP pool access restriction]
+
+** Security Certificates
*** xref:os/letsencrypt.adoc[Using LetsEncrypt certificates]
** Vendors
*** xref:vendors/cisco.adoc[Cisco]
*** xref:vendors/proxim.adoc[ProxIM]
-** Tuning
+** Optimization
+*** xref:monitoring/index.adoc[Monitoring]
+**** xref:monitoring/statistics.adoc[Server Statistics]
*** xref:tuning/performance-testing.adoc[Performance Testing]
*** xref:tuning/tuning_guide.adoc[Tuning Guide]
+
// Copyright (C) 2025 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
// This documentation was developed by Network RADIUS SAS.
--- /dev/null
+= Monitoring
+
+Any good systems administrator will want to know how well
+their systems are operating, both to catch issues before they
+become a serious problem, or for long term analysis.
+The term "monitoring" can encompass all kinds of watching how the
+system is working, from generating and watching logs, gathering
+statistics or ensuring that the service daemon is still running
+and serving requests.
+
+We break the different types of monitoring down into the following
+sections.
+
+== Service checking
+
+Checking the running service can include the following:
+
+* Ensuring the daemon is still running, i.e. process monitoring
+* Sending regular RADIUS authentication or accounting requests and checking they are correctly responded to
+* Sending Status-Server RADIUS requests
+
+Within a proxy environment FreeRADIUS needs to know if upstream
+proxies are available. It can do this itself using the latter two
+options above.
+
+== Logging
+
+System logs are often the most critical part of a RADIUS system.
+They are necessary for the administrator to know who has logged in
+and when, for debugging purposes such as when an end user cannot
+connect, and often for regulatory or compliance purposes.
+
+RADIUS server logs are also often used as a basic form of
+recording accounting requests, which are in and of themselves a
+form of logging by the NAS. Getting correct logging systems
+operational is key to running an efficient and easy to maintain
+RADIUS server.
+
+FreeRADIUS has many options for being able to generate and store
+logs, including the following:
+
+* Main daemon logging, configured in `radiusd.conf`
+* Line-based text logging, using `rlm_linelog`
+* Detailed RADIUS packet logs, using `rlm_detail`
+
+As well as recording direct to disk, the above can be sent via a
+local syslog server, which opens up many opportunities for central
+logging.
+
+It is possible to integrate FreeRADIUS into other more complicated
+logging systems, some options may include:
+
+* To CSV files, for example via `rlm_linelog`
+* Writing entries to an SQL database using `rlm_sql`
+* Into a log management system such as Elasticsearch or Graylog
+
+
+== Statistics gathering
+
+It is often useful to collect statistics from a running RADIUS
+server. These are often plotted on graphs to show current load or
+for trend analysis, as well as an indication of system operation.
+
+Statistics are usually gathered in two ways:
+
+* FreeRADIUS xref:monitoring/statistics.adoc[internal statistics]
+* Analysing logs with some external tool
--- /dev/null
+= Server statistics
+
+FreeRADIUS collects statistics internally about certain operations
+it is doing, such as the number of authentication and accounting
+requests, how many accepts and failures, and server queue lengths.
+These can be queried by sending a specially-crafted RADIUS
+`Status-Server` packet to a "status" virtual server.
+
+== Configuring the status virtual server
+
+The `status` virtual server is present in the default
+configuration, but needs to be enabled before it can be used. To
+do this, create a symlink from `sites-enabled/status` to
+`../sites-available/status`:
+
+[source,shell]
+----
+# cd raddb/sites-enabled
+# ln -s ../sites-available/status
+----
+
+[NOTE]
+====
+If you are not starting from the default configuration, check that
+`status_server` is still set to `yes` in `raddb/radiusd.conf` as
+well.
+====
+
+While the default configuration will work for most setups, you may
+edit the virtual server configuration in `sites-enabled/status`.
+No major changes are necessary here, though the default secret,
+`adminsecret`, should be changed. Other possible changes may be
+the listening IP address and port, and the clients that are
+allowed to connect. By default, connections are restricted to the
+local host only.
+
+Having enabled and configured the status server, restart
+FreeRADIUS to make it active.
+
+== Querying the server
+
+To get the current statistics from the server, send a RADIUS
+request of type `Status-Server` to the status port. Unless edited
+above, the request must come from the same server that FreeRADIUS
+is running on, and be sent to port 18121 with the secret
+'adminsecret' . At a minimum, the `FreeRADIUS-Statistics-Type`
+attribute must be set. For example:
+
+ $ cat <<EOF | radclient -x localhost:18121 status adminsecret
+ > FreeRADIUS-Statistics-Type = 0x01
+ > Message-Authenticator = 0x00
+ > EOF
+ Sent Status-Server Id 145 from 0.0.0.0:b852 to 127.0.0.1:18121 length 62
+ FreeRADIUS-Statistics-Type = Authentication
+ Message-Authenticator = 0x00
+ Received Access-Accept Id 145 from 127.0.0.1:46c9 to 127.0.0.1:47186 length 152
+ FreeRADIUS-Total-Access-Requests = 27
+ FreeRADIUS-Total-Access-Accepts = 20
+ FreeRADIUS-Total-Access-Rejects = 1
+ FreeRADIUS-Total-Access-Challenges = 0
+ FreeRADIUS-Total-Auth-Responses = 5
+ FreeRADIUS-Total-Auth-Duplicate-Requests = 0
+ FreeRADIUS-Total-Auth-Malformed-Requests = 0
+ FreeRADIUS-Total-Auth-Invalid-Requests = 0
+ FreeRADIUS-Total-Auth-Dropped-Requests = 0
+ FreeRADIUS-Total-Auth-Unknown-Types = 0
+ FreeRADIUS-Total-Auth-Conflicts = 0
+
+The `FreeRADIUS-Statistics-Type` attribute is a bitmask - add
+together the following numbers to select the statistics required.
+Some options are mutually exclusive, so it might be necessary to
+send multiple requests to collect all information.
+
+[%header,cols="2,1,1,5"]
+|===
+|Name|Hex value|Decimal value|Description
+
+|Authentication
+|0x01
+|1
+|Stats about authentications
+
+|Accounting
+|0x02
+|2
+|Stats about accounting
+
+|Proxy Auth
+|0x04
+|4
+|Proxied authentication requests
+
+|Proxy Accounting
+|0x08
+|8
+|Proxied accounting requests
+
+|Internal
+|0x10
+|16
+|Queue lengths, thread information etc.
+
+|Client
+|0x20
+|32
+|Statistics about RADIUS clients e.g. defined in `clients.conf`
+
+|Server
+|0x40
+|64
+|Statistics about server 'listen' sockets e.g. in `sites-enabled/*`
+
+|Home Server
+|0x80
+|128
+|Statistics about a proxy home servers e.g. in `proxy.conf`
+|===
+
+== Worked examples
+
+To show the statistics available, a few examples follow.
+
+=== Global server authentications
+
+Using `FreeRADIUS-Statistics-Type = 0x01` requests stats about
+authentications. Because, for example, no "Client" qualifier has
+been added (`0x20`) the numbers are global to the server.
+
+[source,shell]
+----
+# cat <<EOF | radclient -x localhost:18121 status adminsecret
+FreeRADIUS-Statistics-Type = 0x01
+Message-Authenticator=0x00
+EOF
+Sent Status-Server Id 90 from 0.0.0.0:e008 to 127.0.0.1:18121 length 50
+ FreeRADIUS-Statistics-Type = Authentication
+ Message-Authenticator = 0x00
+Received Access-Accept Id 90 from 127.0.0.1:46c9 to 127.0.0.1:57352 length 152
+ FreeRADIUS-Total-Access-Requests = 133
+ FreeRADIUS-Total-Access-Accepts = 114
+ FreeRADIUS-Total-Access-Rejects = 13
+ FreeRADIUS-Total-Access-Challenges = 0
+ FreeRADIUS-Total-Auth-Responses = 127
+ FreeRADIUS-Total-Auth-Duplicate-Requests = 0
+ FreeRADIUS-Total-Auth-Malformed-Requests = 0
+ FreeRADIUS-Total-Auth-Invalid-Requests = 0
+ FreeRADIUS-Total-Auth-Dropped-Requests = 0
+ FreeRADIUS-Total-Auth-Unknown-Types = 0
+ FreeRADIUS-Total-Auth-Conflicts = 0
+----
+
+=== Global server authentication and accounting requests
+
+Sending `0x01` requests authentication statistics, and `0x02`
+requests accounting stats. To get both in one result, add them
+together, so we requst `0x03`. In this example we send decimal
+rather than hexadecimal.
+
+[source,shell]
+----
+# cat <<EOF | radclient -x localhost:18121 status adminsecret
+FreeRADIUS-Statistics-Type = 3
+Message-Authenticator=0x00
+EOF
+Sent Status-Server Id 216 from 0.0.0.0:ce7b to 127.0.0.1:18121 length 50
+ FreeRADIUS-Statistics-Type = Auth-Acct
+ Message-Authenticator = 0x00
+Received Access-Accept Id 216 from 127.0.0.1:46c9 to 127.0.0.1:52859 length 248
+ FreeRADIUS-Total-Access-Requests = 542
+ FreeRADIUS-Total-Access-Accepts = 451
+ FreeRADIUS-Total-Access-Rejects = 81
+ FreeRADIUS-Total-Access-Challenges = 0
+ FreeRADIUS-Total-Auth-Responses = 532
+ FreeRADIUS-Total-Auth-Duplicate-Requests = 0
+ FreeRADIUS-Total-Auth-Malformed-Requests = 0
+ FreeRADIUS-Total-Auth-Invalid-Requests = 0
+ FreeRADIUS-Total-Auth-Dropped-Requests = 0
+ FreeRADIUS-Total-Auth-Unknown-Types = 0
+ FreeRADIUS-Total-Auth-Conflicts = 0
+ FreeRADIUS-Total-Accounting-Requests = 0
+ FreeRADIUS-Total-Accounting-Responses = 0
+ FreeRADIUS-Total-Acct-Duplicate-Requests = 0
+ FreeRADIUS-Total-Acct-Malformed-Requests = 0
+ FreeRADIUS-Total-Acct-Invalid-Requests = 0
+ FreeRADIUS-Total-Acct-Dropped-Requests = 0
+ FreeRADIUS-Total-Acct-Unknown-Types = 0
+ FreeRADIUS-Total-Acct-Conflicts = 0
+----
+
+=== Internal server stats
+
+The value `0x10` requests information about the server such as queue
+lengths and thread state.
+
+[source,shell]
+----
+# cat <<EOF | radclient -x localhost:18121 status adminsecret
+FreeRADIUS-Statistics-Type = 0x10
+Message-Authenticator=0x00
+EOF
+Sent Status-Server Id 158 from 0.0.0.0:a090 to 127.0.0.1:18121 length 50
+ FreeRADIUS-Statistics-Type = Internal
+ Message-Authenticator = 0x00
+Received Access-Accept Id 158 from 127.0.0.1:46c9 to 127.0.0.1:41104 length 164
+ FreeRADIUS-Stats-Start-Time = "Aug 3 2023 13:36:24 UTC"
+ FreeRADIUS-Stats-HUP-Time = "Aug 3 2023 13:36:24 UTC"
+ FreeRADIUS-Queue-Len-Internal = 0
+ FreeRADIUS-Queue-Len-Proxy = 0
+ FreeRADIUS-Queue-Len-Auth = 0
+ FreeRADIUS-Queue-Len-Acct = 0
+ FreeRADIUS-Queue-Len-Detail = 0
+ FreeRADIUS-Queue-PPS-In = 0
+ FreeRADIUS-Queue-PPS-Out = 0
+ FreeRADIUS-Stats-Threads-Active = 0
+ FreeRADIUS-Stats-Threads-Total = 0
+ FreeRADIUS-Stats-Threads-Max = 0
+----
+
+=== Complete global server information
+
+A useful common request is all information about the server on a
+global basis: internal stats (16 / `0x10`) plus authentications (1
+/ `0x01`), accounting (2 / `0x02`), proxy authentications (4 /
+`0x04`) and proxy accounting (8 / `0x08`). The value `All` is
+defined in the dictionary as `0x1f` (decimal 31) to cover
+this common eventuality, and is what we demonstrate here.
+
+[source,shell]
+----
+# cat <<EOF | radclient -x localhost:18121 status adminsecret
+FreeRADIUS-Statistics-Type = All
+Message-Authenticator=0x00
+EOF
+Sent Status-Server Id 4 from 0.0.0.0:9ee4 to 127.0.0.1:18121 length 50
+ FreeRADIUS-Statistics-Type = All
+ Message-Authenticator = 0x00
+Received Access-Accept Id 4 from 127.0.0.1:46c9 to 127.0.0.1:40676 length 596
+ FreeRADIUS-Total-Access-Requests = 792
+ FreeRADIUS-Total-Access-Accepts = 659
+ FreeRADIUS-Total-Access-Rejects = 122
+ FreeRADIUS-Total-Access-Challenges = 0
+ FreeRADIUS-Total-Auth-Responses = 781
+ FreeRADIUS-Total-Auth-Duplicate-Requests = 0
+ FreeRADIUS-Total-Auth-Malformed-Requests = 0
+ FreeRADIUS-Total-Auth-Invalid-Requests = 0
+ FreeRADIUS-Total-Auth-Dropped-Requests = 0
+ FreeRADIUS-Total-Auth-Unknown-Types = 0
+ FreeRADIUS-Total-Auth-Conflicts = 0
+ FreeRADIUS-Total-Accounting-Requests = 0
+ FreeRADIUS-Total-Accounting-Responses = 0
+ FreeRADIUS-Total-Acct-Duplicate-Requests = 0
+ FreeRADIUS-Total-Acct-Malformed-Requests = 0
+ FreeRADIUS-Total-Acct-Invalid-Requests = 0
+ FreeRADIUS-Total-Acct-Dropped-Requests = 0
+ FreeRADIUS-Total-Acct-Unknown-Types = 0
+ FreeRADIUS-Total-Acct-Conflicts = 0
+ FreeRADIUS-Total-Proxy-Access-Requests = 0
+ FreeRADIUS-Total-Proxy-Access-Accepts = 0
+ FreeRADIUS-Total-Proxy-Access-Rejects = 0
+ FreeRADIUS-Total-Proxy-Access-Challenges = 0
+ FreeRADIUS-Total-Proxy-Auth-Responses = 0
+ FreeRADIUS-Total-Proxy-Auth-Duplicate-Requests = 0
+ FreeRADIUS-Total-Proxy-Auth-Malformed-Requests = 0
+ FreeRADIUS-Total-Proxy-Auth-Invalid-Requests = 0
+ FreeRADIUS-Total-Proxy-Auth-Dropped-Requests = 0
+ FreeRADIUS-Total-Proxy-Auth-Unknown-Types = 0
+ FreeRADIUS-Total-Proxy-Accounting-Requests = 0
+ FreeRADIUS-Total-Proxy-Accounting-Responses = 0
+ FreeRADIUS-Total-Proxy-Acct-Duplicate-Requests = 0
+ FreeRADIUS-Total-Proxy-Acct-Malformed-Requests = 0
+ FreeRADIUS-Total-Proxy-Acct-Invalid-Requests = 0
+ FreeRADIUS-Total-Proxy-Acct-Dropped-Requests = 0
+ FreeRADIUS-Total-Proxy-Acct-Unknown-Types = 0
+ FreeRADIUS-Stats-Start-Time = "Aug 3 2023 13:36:24 UTC"
+ FreeRADIUS-Stats-HUP-Time = "Aug 3 2023 13:36:24 UTC"
+ FreeRADIUS-Queue-Len-Internal = 0
+ FreeRADIUS-Queue-Len-Proxy = 0
+ FreeRADIUS-Queue-Len-Auth = 0
+ FreeRADIUS-Queue-Len-Acct = 0
+ FreeRADIUS-Queue-Len-Detail = 0
+ FreeRADIUS-Queue-PPS-In = 0
+ FreeRADIUS-Queue-PPS-Out = 0
+ FreeRADIUS-Stats-Threads-Active = 0
+ FreeRADIUS-Stats-Threads-Total = 0
+ FreeRADIUS-Stats-Threads-Max = 0
+----
+
+=== Client statistics
+
+Data can be provided about each RADIUS client defined in the
+server. Note that this is for the client definition, not for each
+client that connects - if a client definition has a wide netmask
+and permits multiple clients to connect, the statistics will be
+aggregate for all clients using that definition.
+
+[NOTE]
+====
+It is not possible to request global server statistics
+concurrently with client statistics as both use the same reply
+attributes.
+====
+
+Here we request accounting data for one particular client by IP
+address.
+
+[source,shell]
+----
+# cat <<EOF | radclient -x localhost:18121 status adminsecret
+FreeRADIUS-Statistics-Type = 0x2f
+FreeRADIUS-Stats-Client-IP-Address = 172.16.0.10
+Message-Authenticator=0x00
+EOF
+Sent Status-Server Id 194 from 0.0.0.0:d897 to 127.0.0.1:18121 length 62
+ FreeRADIUS-Statistics-Type = 47
+ FreeRADIUS-Stats-Client-IP-Address = 172.16.0.10
+ Message-Authenticator = 0x00
+Received Access-Accept Id 194 from 127.0.0.1:46c9 to 127.0.0.1:55447 length 236
+ FreeRADIUS-Stats-Client-IP-Address = 172.16.0.10
+ FreeRADIUS-Total-Access-Requests = 1491
+ FreeRADIUS-Total-Access-Accepts = 1240
+ FreeRADIUS-Total-Access-Rejects = 246
+ FreeRADIUS-Total-Access-Challenges = 0
+ FreeRADIUS-Total-Auth-Responses = 1486
+ FreeRADIUS-Total-Auth-Duplicate-Requests = 0
+ FreeRADIUS-Total-Auth-Malformed-Requests = 0
+ FreeRADIUS-Total-Auth-Invalid-Requests = 0
+ FreeRADIUS-Total-Auth-Dropped-Requests = 0
+ FreeRADIUS-Total-Auth-Unknown-Types = 0
+ FreeRADIUS-Total-Accounting-Requests = 0
+ FreeRADIUS-Total-Accounting-Responses = 0
+ FreeRADIUS-Total-Acct-Duplicate-Requests = 0
+ FreeRADIUS-Total-Acct-Malformed-Requests = 0
+ FreeRADIUS-Total-Acct-Invalid-Requests = 0
+ FreeRADIUS-Total-Acct-Dropped-Requests = 0
+ FreeRADIUS-Total-Acct-Unknown-Types = 0
+----
certificate for your RADIUS server, and are aware of the
security considerations in doing so.
-- You wish to use [LetsEncrypt[(https://letsencrypt.org/) for this
+- You wish to use https://letsencrypt.org/[LetsEncrypt[ for this
purpose, and want certificate renewals (usually every 2-3 months) to
be automatic.
== Set up process
-The instructions here use LetsEncrypt's [certbot](https://certbot.eff.org/) tool to generate
+The instructions here use LetsEncrypt's https://certbot.eff.org/[certbot] tool to generate
certificates and renew them when necessary. Other alternative
tools can be used based on the following instructions.
based systems, `radius` if installed from source, or some other
user.
-NOTE: You *must* have a public IP address for the server, and
+[NOTE]
+===
+You *must* have a public IP address for the server, and
there *must* be a DNS entry (of the name of the certificate you
will be requesting) pointing to this IP. The server *must* be
reachable on port 80 (HTTP) from the Internet.
+===
Install the `certbot` utility from LetsEncrypt. On Debian it can
be installed from the default repositories:
you are quickly locked out if making multiple requests while testing.
It is therefore useful to try with the test issuer first.
-Run the following to generate a key and to request the certificate.
-Note that `certbot` will open up a temporary web server on port 80
-while this is in progress, so ensure that any firewalls are already
-opened up, and that external systems can connect to the machine in
-port 80.
+Run the following set of commands to generate a key and to request the certificate.
+.Generate a test certificate
+[%collapsible]
+====
[source,shell]
----
certbot certonly \
-d radius.example.com \
--post-hook /usr/local/sbin/certbot-post-hook
----
+====
+
+[NOTE]
+====
+The `certbot` opens up a temporary web server on port 80
+while this is in progress. Ensure that any firewalls are already
+opened up, and that external systems can connect to the machine in
+port 80.
+====
Any issues generating this certificate pair need to be
investigated and fixed. Repeat the above command as necessary
until the certificate is issued successfully.
-NOTE: There are still rate limits on LetsEncrypt's test server,
+[NOTE]
+====
+There are still rate limits on LetsEncrypt's test server,
but they are higher and you are less likely to hit them than with
the production issuer.
+====
Once you have successfully generated a test certificate, you can
remove it and request the real certificate:
+.Generate a real certificate
+[%collapsible]
+====
[source,shell]
----
certbot revoke \
-d radius.example.com \
--post-hook /usr/local/sbin/certbot-post-hook
----
-
+====
=== FreeRADIUS configuration
--- /dev/null
+== Enabling the DHCP service
+
+A major difference between configuring FreeRADIUS as a DHCP server versus most
+other DHCP software such as ISC DHCP is that other software typically uses a
+single monolithic configuration file whereas FreeRADIUS has a collection of
+configuration files. This reflects the modularity of FreeRADIUS; attempting to
+put the entire configuration in a single file would result in a very difficult
+to read configuration.
+
+The root of the FreeRADIUS configuration may be in a different location on the
+filesystem depending on how FreeRADIUS has been installed. This directory will
+be referred to as `<raddb>` below. The sample configuration files are well
+commented describing what each configuration option does.
+
+FreeRADIUS compiled from source will default to `/usr/local/etc/raddb`.
+Pre-built packages will default to either `/etc/raddb` or
+`/etc/freeradius`.
+
+
+=== Enable the DHCP virtual server
+
+The FreeRADIUS configuration separates each network service that it provides
+into "virtual servers". A number of sample virtual server definitions are
+provided in `<raddb>/sites-available`, one of which is the sample
+configuration for a DHCP service.
+
+Sites may be added to the working configuration by either creating a symlink to
+them or copying them to `<conf>/sites-enabled` depending on how you wish to
+manage future upgrades.
+
+[TIP]
+====
+As with other package-managed configuration files, package upgrades will not
+automatically replace files that you have edited but you will need to resolve
+any local differences. Creating copies avoids the need to resolve conflicts
+during a package upgrade.
+====
+
+Add the DHCP virtual server to the active configuration:
+
+[source,shell]
+----
+cd <raddb>/sites-enabled
+ln -s ../sites-available/dhcp .
+----
+
+or:
+
+[source,shell]
+----
+cd <raddb>/sites-enabled
+cp ../sites-available/dhcp .
+----
+
+The sample configuration has been set up in such a way that it is initially
+safe. It will not actually take over live DHCP serving on the network when it
+is simply enabled until it is configured to do so. Rather is set up for testing
+prior to going live.
+
+The virtual server begins with a `listen` section. In this section your need to
+modify the following configuration items:
+
+`ipaddr`:: The IP address to listen on.
+`src_ipaddr`:: The source IP for unicast packets.
+`port`:: The port to listen on. Setting this to `67` will make the DHCP service live on the network.
+`interface`:: The network interface to listen on.
+`broadcast`:: Allow broadcast packets. For most live systems this will need to be set to `yes`.
+
+Below the `listen` section, there are sections that define how to respond to
+each of the DHCP packet types. Most installations will require that you review
+the settings for `DHCP-Discover` and `DHCP-Request`.
+
+Their contents contain directives in the FreeRADIUS policy language, "unlang".
+Many examples are provided which have been carefully described.
+
+
+=== Enable SQL and IP pool modules
+
+FreeRADIUS has many modules to support different aspects of the functionality
+required for the network protocols it can process. The two of most significance
+for DHCP are `dhcp_sql` and `dhcp_sqlippool`. As with virtual servers, a
+number of example module configurations are available in
+`<raddb>/mods-available`.
+These should be symlinked or copied into `<raddb>/mods-enabled` in order to
+enable them.
+
+
+==== Configure the `dhcp_sql` module
+
+Add the `dhcp_sql` module to the active configuration:
+
+[source,shell]
+----
+cd <raddb>/mods-enabled
+ln -s ../mods-available/dhcp_sql .
+----
+
+or:
+
+[source,shell]
+----
+cd <raddb>/mods-enabled
+cp ../mods-available/dhcp_sql .
+----
+
+The `dhcp_sql` module should be configured with the connection parameters for
+whichever database is to be used. The key configuration items are:
+
+`dialect`:: Which SQL dialect is in use.
+`driver`:: Which driver to use to access the database. For most databases this
+ is `rlm_sql_<dialect>`, however Microsoft SQL Server has a choice of
+ drivers.
+
+Then, there are configuration options that are unique to each database,
+including connection details. For most databases these are:
+
+`server`:: The host name or IP address of the database server.
+`port`:: The port to connect to the database server on.
+`login`:: The user name used to connect to the database.
+`password`:: The password for authenticating to the database.
+`radius_db`:: The name of the database.
+
+[NOTE]
+====
+SQLite does not use these connection options, rather the `filename`
+option within the `sqlite` section is used to determine where the database
+will be stored.
+====
+
+
+==== Configure the `dhcp_sqlippool` module
+
+Add the `dhcp_sqlippool` module to the active configuration:
+
+[source,shell]
+----
+cd <raddb>/mods-enabled
+ln -s ../mods-available/dhcp_sqlippool .
+----
+
+or
+
+[source,shell]
+----
+cd <raddb>/mods-enabled
+cp ../mods-available/dhcp_sqlippool .
+----
+
+The `dhcp_sqlippool` module must be configured. The key configuration
+items are:
+
+`dialect`:: Set this to the same SQL dialect as in the `sql` module.
+`offer_duration`:: How long an IP is offered to the client in a DHCP OFFER.
+`lease_duration`:: How long an IP is leased to the client in a DHCP ACK.
+
+
+=== Provision the database
+
+You should provision your database by creating a user for FreeRADIUS (matching
+the configuration that you have previously provided) and then loading the
+schema. The procedure for doing this will vary according to the database
+server.
+
+The schema, stored procedure definition and any additional setup scripts for
+your database are in `<raddb>/mods-config/sql/ippool-dhcp/{dialect}/`.
+
+=== Test FreeRADIUS startup
+
+Once you have provisioned your schema, created a user account and granted
+access to the user, you should be able to start FreeRADIUS.
+
+If FreeRADIUS has been configured correctly then the output of `ss` will
+contain a line showing that FreeRADIUS is listening for DHCP packets on the
+designated interface on port 67:
+
+.Example of FreeRADIUS listening on `<interface>` for DHCP packets
+==================================================================
+ # ss -lunp
+ Netid Recv-Q Send-Q Local Address:Port ...
+ udp 0 0 0.0.0.0%<interface>:67 ... users:(("radiusd",...))
+==================================================================
+
+Note that if the database is inaccessible then FreeRADIUS will normally refuse
+to start.
+
+The FreeRADIUS wiki contains extensive information about debugging FreeRADIUS
+startup issues that we do not repeat in any detail here.
+
+Essentially, stop your init system from repeatedly trying to launch FreeRADIUS:
+
+[source,shell]
+----
+service radiusd stop
+----
+
+Then start FreeRADIUS manually in debug mode:
+
+[source,shell]
+----
+radiusd -X
+----
+
+Carefully read the output since this will tell you why FreeRADIUS was unable to
+start.
+
+Once you have fixed the issue start FreeRADIUS as normal:
+
+[source,shell]
+----
+service radiusd start
+----
+
+Now xref:protocols/dhcp/test.adoc[test the DHCP service] to ensure that it is responding to requests.
--- /dev/null
+= FreeRADIUS DHCP server
+
+This guide describes how FreeRADIUS can be used in place of ISC DHCP or ISC Kea
+to provide a significantly more performant and, above all, more flexible DHCP
+server.
+
+This guide provides a suggested configuration that should be somewhat familiar
+to anyone who has previously implemented DHCP using the most frequently used
+features of other DHCP server software.
+
+The modular design of FreeRADIUS means that there is no one "right" way to
+implement the DHCP service. FreeRADIUS allows you to put together a "mix and
+match" approach.
+
+For example you can manage the leases in an SQL database. You might then hard
+code certain DHCP reply parameters within configuration and then look up
+additional parameters using a datastore such as:
+
+ * a local file such as a structured text file or an SQLite database
+ * an organisational LDAP directory
+ * an SQL or "no SQL" database
+ * a remote endpoint such as a RESTful HTTP API
+
+The policy language and modular configuration of FreeRADIUS is sufficiently
+powerful and that almost any aspect of the server's behaviour can be customised
+to implement even the most sophisticated DHCP configurations.
+
+== Sections in this guide
+
+This guide is organised into four parts that should be read in order:
+
+1. xref:protocols/dhcp/prepare.adoc[Preparation]
+2. xref:protocols/dhcp/enable.adoc[Enabling the DHCP service]
+3. xref:protocols/dhcp/test.adoc[Testing the DHCP service]
+4. xref:protocols/dhcp/policy.adoc[Defining the DHCP policy]
--- /dev/null
+== Defining the DHCP policy
+
+Now that FreeRADIUS is successfully running as a DHCP server it is necessary to
+configure a DHCP policy so that it returns correctly formed responses to the DHCP
+requests that it receives.
+
+This involves a number of steps:
+
+ * xref:protocols/dhcp/policy_ippool_creation.adoc[Defining the IP address pools.]
+ * xref:protocols/dhcp/policy_common_options.adoc[Defining the options that are common to all replies.]
+ * xref:protocols/dhcp/policy_network_options.adoc[Defining the options for the network from which the request originates and ensuring that IP addresses are allocated from the correct pool.]
+ * xref:protocols/dhcp/policy_subnet_options.adoc[Defining the options for the subnet to which this issued IP address belongs.]
+ * xref:protocols/dhcp/policy_device_options.adoc[Defining the device, class and group based options specific to the device.]
+ * xref:protocols/dhcp/policy_ippool_access.adoc[Using device properties to restrict access to certain pools.]
--- /dev/null
+== Configure common reply options
+
+FreeRADIUS includes a powerful xref:index.adoc[policy language] called
+"unlang".
+
+Statements in unlang may be used to call further policies, update attribute
+lists and invoke modules. There are also control flow statements (if,
+switch, etc.) typical of most imperative languages.
+
+FreeRADIUS has a number attribute lists that it maintains as it processes
+packets within the virtual server sections. Most relevant to DHCP are
+`request`, `control` and `reply`.
+
+The DHCP options from the current request packet are provided in the
+`request` list. This includes fixed DHCP parameters such as
+`DHCP-Client-Hardware-Address`, optional parameters such as
+`DHCP-Requested-IP-Address`, and parameters synthesised by FreeRADIUS such as
+`DHCP-Message-Type` and `DHCP-Network-Subnet`.
+
+DHCP options can be set by updating their value in the `reply` list. This
+forms the basis of the packet returned to the client.
+
+In the default DHCP server configuration, a "policy" (akin to a subroutine) is
+used to set common options for reply packets. The policy is found in
+`<raddb>/policy.d/dhcp`.
+
+Look at the contents of the `dhcp_common` section and set any global options
+applicable to all clients in this policy.
+
+[source,unlang]
+----
+dhcp_common {
+ update reply {
+ &DHCP-Domain-Name-Server := 8.8.8.8
+ &DHCP-Domain-Name-Server += 8.8.4.4
+ &DHCP-Subnet-Mask := 255.255.255.0
+ &DHCP-Router-Address := 192.0.2.1
+ ...
+ }
+}
+----
+
+Note, FreeRADIUS has four main operators for assigning values to attributes:
+
+`=`:: Add the attribute to the list, if and only if an attribute of the same
+ name is not already present in that list.
+`:=`:: Add the attribute to the list. If any attribute of the same name is
+ already present in that list it is replaced with the new one.
+`+=`:: Add the attribute to the tail of the list, even if attributes of the
+ same name are already present in the list.
+`^=`:: Add the attribute to the head of the list, even if attributes of the
+ same name are already present in the list.
+
+These operators allow for attributes to be set to default values and then
+overwritten, e.g. setting a default lease time, but then overwriting it for
+a particular group of clients.
+
+Attributes in the `control` list are not returned in the DHCP reply packets
+but instead govern aspects of server's behaviour.
+
+To use an SQL backend for either static or dynamic IP allocation, un-comment
+the block:
+
+[source,unlang]
+----
+update control {
+ &Pool-Name := "local"
+}
+dhcp_sqlippool
+----
+
+The `Pool-Name` control attribute is used in looking up addresses in the
+database. The line containing `dhcp_sqlippool` is a call to invoke an
+instance of a module with that name. This module is responsible for assigning a
+free IP address into the `DHCP-Your-IP-Address` reply attribute from the pool
+identified by `Pool-Name`.
+
+Here `Pool-Name` is being set to a constant value (`local`) indicating
+that a single pool is to be used. If you have multiple pools, then replace this
+`update` block with logic to map clients to the correct pool, as described below.
--- /dev/null
+== 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 `DHCP-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
+`DHCP-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 `DHCP-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:
+
+[source,iscdhcp]
+----
+filename "undionly.kpxe";
+class "pxeclient" {
+ match option substring(user-class,0,4);
+}
+subclass "pxeclient" "iPXE" {
+ filename "http://my.web.server/boot_script.php";
+}
+----
+
+Or the equivalent Kea configuration:
+
+[source,isckea]
+----
+"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:
+
+[source,unlang]
+----
+if (&DHCP-User-Class && "%{substring:&DHCP-User-Class 0 4}" == "iPXE") {
+ update reply {
+ &DHCP-Boot-Filename := "http://my.web.server/boot_script.php"
+ }
+} else {
+ update reply {
+ &DHCP-Boot-Filename := "undionly.kpxe"
+ }
+}
+----
+
+Policy-based configuration of DHCP options is also useful for complex matching.
+For example, the following Unlang sets the DHCP-Boot-Filename parameter based
+on the request's DHCP-Client-Identifier using regular expression captures,
+provided that it matches the given format:
+
+[source,unlang]
+----
+if (&DHCP-Client-Identifier && \
+ "%{string:DHCP-Client-Identifier}" =~ /^RAS([0-9])-site([A-Z])$/) {
+ update reply {
+ &DHCP-Boot-Filename := "rasboot-%{1}-%{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, for
+which a sample configuration is included.
+
+Firstly symlink or copy the module configuration
+`<raddb>/mods-available/dhcp_passwd` into `<raddb>/mods-enabled/`. The
+suggested configuration expects the group membership file to be in
+`<raddb>/mods-config/files/dhcp_groups` and take the form of:
+
+[source,config]
+----
+<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.
+
+Sample configuration for looking up group options is contained in
+`<raddb>/policy.d/dhcp` in the `dhcp_group_options` policy and in
+`<raddb>/mods-available/dhcp_files` as the `dhcp_set_group_options` instance.
+
+The same data file `<raddb>/mods-config/files/dhcp` is used to lookup
+group options as was used for global and network options. In this instance,
+add entries with the group name as the key such as:
+
+[source,config]
+----
+group1
+ DHCP-Log-Server := 10.10.0.100,
+ DHCP-LPR-Server := 10.10.0.200
+
+group2
+ DHCP-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 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.
+
+The default schema contains three tables to support this:
+
+"dhcpreply" contains reply options for a given identifier (e.g. MAC Address):
+
+.dhcpreply table
+|===
+|Identifier |Attribute |Op |Value |Context
+
+|`02:01:aa:bb:cc:dd` |`DHCP-Log-Server` |`:=` |`192.0.2.10` |`by-mac`
+|`02:01:aa:bb:cc:dd` |`DHCP-LPR-Server` |`:=` |`192.0.2.11` |`by-mac`
+|`02:01:aa:bb:cc:dd` |`Fall-Through` |`:=` |`Yes` |`by-mac`
+|===
+
+"dhcpgroup" maps identifiers to a group of options that can be shared:
+
+.dhcpgroup table
+|===
+|Identifier |GroupName |Priority |Context
+
+|`02:01:aa:bb:cc:dd` |`salesdept` |`10` |`by-mac`
+|===
+
+"dhcpgroupreply" contains reply options for each group:
+
+.dhcpgroupreply table
+|===
+|GroupName |Attribute |Op |Value |Context
+
+|`salesdept` |`DHCP-NTP-Servers` |`:=` |`192.0.2.20` |`by-mac`
+|`salesdept` |`DHCP-Log-Server` |`+=` |`192.0.2.21` |`by-mac`
+|`salesdept` |`DHCP-LPR-Server` |`^=` |`192.0.2.22` |`by-mac`
+|===
+
+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 "dhcpreply" table.
+ - Add `Fall-Through := Yes` to the options in the "dhcpreply" table in order
+ to trigger group lookups, which are disabled by default.
+ - Place entries in the "dhcpgroup" `identifier = <MAC-Address>, groupname = <group>, priority =
+ <priority>` in the "dhcpgroup" table to map a device to its groups by
+ priority.
+ - Place the grouped options in the "dhcpgroupreply" table.
+ - For each of the above, set `Context` to something by which the option
+ lookup is referred to in the policy, for example `Context = 'by-mac'`.
+
+For the above example you would add the following to the DHCP virtual server to
+perform reply option lookup using the device's MAC address against the `by-mac`
+context:
+
+[source,unlang]
+----
+update control {
+ &DHCP-SQL-Option-Context := "by-mac"
+ &DHCP-SQL-Option-Identifier := &request:DHCP-Client-Hardware-Address
+}
+dhcp_sql.authorize
+----
+
+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 `DHCP-Log-Server` option would be set to `192.0.2.10` and the
+ `DHCP-LPR-Server` option set to `192.0.2.11`.
+ - `Fall-Through` is set, so the group mapping is then queried which
+ determines that the device belongs to a single `salesdept` group.
+ - Finally, the options for the `salesdept` group are now merged, setting a
+ `DHCP-NTP-Servers` option to `192.0.2.20`, appending an additional
+ `DHCP-Log-Server` option set to `192.0.2.21`, and prepending an additional
+ `DHCP-LPR-Server` option set to `192.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:
+
+."dhcpreply" table:
+|===
+|Identifier |Attribute |Op |Value |Context
+
+|`000393` |`Fall-Through` |`:=` |`Yes` |`class-vendor`
+|`000a27` |`Fall-Through` |`:=` |`Yes` |`class-vendor`
+|`f40304` |`Fall-Through` |`:=` |`Yes` |`class-vendor`
+|===
+
+."dhcpgroup" table:
+|===
+|Identifier |GroupName |Priority |Context
+
+|`000393` |`apple` |`10` |`class-vendor`
+|`000a27` |`apple` |`10` |`class-vendor`
+|`f40304` |`google` |`10` |`class-vendor`
+|===
+
+."dhcpgroupreply" table:
+|===
+|GroupName |Attribute |Op |Value |Context
+
+|`apple` |`DHCP-Boot-Filename` |`:=` |`apple.efi` |`class-vendor`
+|`google` |`DHCP-Boot-Filename` |`:=` |`google.efi` |`class-vendor`
+|===
+
+
+[source,unlang]
+----
+update control {
+ &DHCP-SQL-Option-Context := "class-vendor"
+ &DHCP-SQL-Option-Identifier := \
+ "%{substring:%{hex:&DHCP-Client-Hardware-Address} 0 6}"
+}
+dhcp_sql.authorize
+----
+
+The file `policy.d/dhcp` contains a policy named `dhcp_policy_sql` which
+provides further worked examples for different types of option lookups.
+
+=== Testing "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:
+
+[source,shell]
+----
+cat <<EOF > dhcp-packet-ipxe-boot.txt
+DHCP-Message-Type := DHCP-Discover
+DHCP-Client-Hardware-Address := 02:01:aa:bb:cc:dd
+DHCP-User-Class := "iPXE-class-abc"
+EOF
+----
+
+To which you would expect to see a response such as:
+
+.Example output from dhcpclient
+===============================
+ dhcpclient: ...
+ ----------------------------------------------------------------------
+ Waiting for DHCP replies for: 5.000000
+ ----------------------------------------------------------------------
+ ...
+ DHCP-Message-Type = DHCP-Offer
+ DHCP-Your-IP-Address = 1.2.3.4
+ DHCP-Boot-Filename := "http://my.web.server/boot_script.php"
+ ...
+===============================
--- /dev/null
+== Configure access restrictions for pools
+
+We can combine what we have learned in the preceeding sections to provide pools
+whose access is restricted in some way, for example to a particular class.
+
+Consider the ISC DHCP configuration snippet:
+
+[source,iscdhcp]
+----
+subnet 10.99.99.0 netmask 255.255.255.0 {
+ pool {
+ range 10.99.99.200 10.99.99.250;
+ allow members of "printers";
+ }
+ option routers 10.99.99.1;
+}
+----
+
+Or the equivalent Kea configuration:
+
+[source,isckea]
+----
+"Dhcp4": {
+ "subnet4": [{
+ "subnet": "10.99.99.0/24",
+ "pools": [
+ {
+ "pool": "10.99.99.200 - 10.99.99.250",
+ "client-class": "printers"
+ }
+ ],
+ "option-data": [
+ { "name": "routers", "data": "10.10.0.1" }
+ ]
+ }],
+ ...
+}
+----
+
+These define a subnet containing a single pool that is restricted to members of
+the "printers" class. (The definition for this class is omitted.)
+
+In FreeRADIUS, to filter access to this pool entries such as the following
+should included in the `<raddb>/mods-config/files/dhcp` configuration file:
+
+[source,config]
+----
+network DHCP-Network-Subnet < 10.99.99.0/24, \
+ DHCP-Group-Name == "printers", Pool-Name := "printers-pool"
+ DHCP-Router-Address := 10.99.99.1
+----
+
+Note that any number of additional filters can be added to the initial "check"
+line to restrict matches to the network block.
--- /dev/null
+=== Determine the IP pool plan
+
+Except for cases where all IP allocation is performed using a mapping from the
+device MAC address to a fixed IP address, the DHCP configuration will involve
+the use of one or more IP address pools.
+
+FreeRADIUS stores all the IP addresses in its pools in whichever database has
+been chosen. An instance of the `sqlippools` module is used to manage all pools
+within a single table (normally `dhcpippool`). Each row of this table
+corresponds to an IP address that is a member of some pool. The pools are
+distinguished by name, so the table has a column (`pool_name`) that denotes
+this.
+
+Each pool in this table should be composed of a set of equally valid IP
+addresses for the devices that are designated to be members of the pool.
+
+Firstly, consider the network locations to which distinct ranges of IP
+addresses must be allocated and provisionally assign a pool to each.
+
+Next, consider that many networks support multiple co-existing subnets without
+VLAN separation. We will call this a "shared-network" to use the original ISC
+DHCP parlance. In Microsoft DHCP contexts this is often referred to as a
+"multinet".
+
+Often in a shared-network the policy has no regard for which of the network's
+devices is allocated to which subnet. In this case we must create a single,
+combined pool containing all of the IP addresses from each subnet in that
+network. Since all addresses in a pool are treated equally this will mean that
+any IP address may be allocated to a device that is making a DHCP request from
+that network. The appropriate DHCP parameters for the subnet to which the IP
+address belongs is determined after allocation.
+
+There are sometimes shared-networks (or even single subnets) for which IP
+addresses belonging to any subnet may be technically suitable for any device,
+however some local policy wants to assigning them to a particular subnet, for
+example to provide loose segregation between classes of device. In this case we
+define multiple pools, one for each range of IP addresses whose devices needs to
+be differentiated.
+
+The choice of pool is ordinarily determined based on the network from which the
+request originates using a mapping from Layer 2 networks to the pool name
+provided by the user. The indicator for the originating network can be
+overridden when this alone is insufficient to implement the required pool
+selection policy such as when you need to differentiate the pool's users with
+more granularity that their Layer 2 network, such as by considering device
+attributes ("class" membership in ISC parlance) or Option 82 circuit data.
+
+
+=== Populate the IP Pools
+
+By this stage you should have derived a list of pools, the IP address ranges
+contained therein, and the means of selecting the pool to use based on the
+originating network and/or some additional criteria from the request.
+
+A helper Perl script is provided with FreeRADIUS that can be used to populate
+the pools provide that you are using the default schema.
+
+[source,shell]
+----
+rlm_sqlippool_tool -p <pool_name> -s <range_start> -e <range_end> \
+ -t <table_name> (-d <sql_dialect> | -f <raddb_dir> [ -i <instance> ]) \
+ [ -c <capacity> ] [ -x <existing_ips_file> ]
+----
+
+If, for example, you had a range configured in ISC DHCP as:
+
+[source,iscdhcp]
+----
+range 10.0.0.5 10.0.0.199
+----
+
+and you are using PostgreSQL as your database, and you wish to refer to this pool
+using the name `local`, this could be prepared with:
+
+[source,shell]
+----
+rlm_sqlippool_tool -p local -s 10.0.0.5 -e 10.0.0.199 -t dhcpippool -d postgresql
+----
+
+If the SQL module of FreeRADIUS is already configured then this can
+be referenced so that the tool is able to use the configured connection
+parameters to connect to the database and populate the pool:
+
+[source,shell]
+----
+rlm_sqlippool_tool -p local -s 10.0.0.5 -e 10.0.0.199 -t dhcpippool -f /etc/raddb
+----
+
+For installations that require multiple pools, `rlm_sqlippool_tool` can
+be called referencing a YAML file defining the pools. Comments at the
+head of `rlm_sqlippool_tool` explain the options in more detail.
+
+If static leases are required then these should be set up in the database
+such that the MAC address of the client should be set as the `pool_key`
+against the corresponding address and the `status` column of the row
+representing the address set to `static`. A helper perl script,
+`rlm_iscfixed2ippool` can be used to read an ISC DHCP config file and produce
+SQL to perform these changes or directly update the database:
+
+[source,shell]
+----
+rlm_iscfixed2ippool -c <dhcpd.<raddb> -t <table_name> -k <mac|id> \
+ (-d <sql_dialect> | -f <raddb_dir> [-i <instance>])
+----
+
+For example, to read /etc/dhcp/dhcpd.conf and populate the configured
+FreeRADIUS database, using the mac as the identifier:
+
+[source,shell]
+----
+rlm_iscfixed2ippool -c /etc/dhcp/dhcpd.conf -t dhcpippool -k mac -f /usr/local/etc/raddb
+----
--- /dev/null
+== Configure network-specific options and IP pool selection
+
+In an environment where multiple networks (often VLANs) are in use, it is
+necessary to identify which network a client belongs to in order to assign an
+address from the correct pool.
+
+Consider the ISC DHCP configuration snippet:
+
+[source,iscdhcp]
+----
+option domain-name "example.org";
+
+subnet 10.10.0.0 netmask 255.255.0.0 {
+ range 10.10.1.10 10.10.10.254;
+ range 10.10.100.10 10.10.110.254;
+ option routers 10.10.0.1;
+ option domain-name-servers 10.10.0.2, 10.10.0.3;
+ default-lease-time 7200;
+}
+----
+
+Or the equivalent Kea configuration:
+
+[source,isckea]
+----
+"Dhcp4": {
+ "option-data": [
+ { "name": "domain-name", "data": "example.org" }
+ ],
+ "subnet4": [{
+ "subnet": "10.10.0.0/16",
+ "pools": [ { "pool": "10.10.1.10 - 10.10.10.254" },
+ { "pool": "10.10.100.10 - 10.10.110.254" }
+ ],
+ "option-data": [
+ { "name": "routers", "data": "10.10.0.1" },
+ { "name": "domain-name-servers", "data": "10.10.0.2, 10.10.0.3" }
+ ],
+ "valid-lifetime": 7200
+ }],
+ ...
+}
+----
+
+These define a network consisting of a single subnet 10.10.0.0/16 containing two
+IP address pools 10.10.1.10 - 10.10.10.254 and 10.10.100.10 - 10.10.110.254.
+Requests that are determined to have originated from this network (e.g. because
+their `giaddr` belongs within the subnet) will be assigned the specified DHCP
+parameters and allocated an address from one of its ranges.
+
+To provide equivalent functionality, FreeRADIUS must identify the correct DHCP
+reply parameters as well as the name of the pool to be used for IP address
+assignment, based on the originating network of the request.
+
+The definition for this pool (the addresses contained within it, corresponding
+to the `range` statement in ISC DHCP and Kea) is specified entirely in the
+database: It is precisely the rows in the `dhcpippool` table with a particular
+`pool_name`.
+
+[TIP]
+====
+As described previously, in FreeRADIUS a pool is a set of IP addresses that are
+equally valid with respect to the network policy; therefore, unlike ISC DHCP
+and ISC Kea, FreeRADIUS does not differentiate between the two `range`s.
+Instead we should have previously populated a single pool containing all of the
+IP addresses from both ranges.
+====
+
+FreeRADIUS derives a request attribute called `DHCP-Network-Subnet` which
+honours the standard DHCP process for designating the choice of network, in
+order of preference:
+
+ 1. Link Selection Suboption of Option 82
+ 2. IPv4 Subnet Selection Option
+ 3. Gateway IP Address ("giaddr")
+ 4. Client IP Address ("ciaddr", only set for unicast packets)
+
+If `DHCP-Network-Subnet` contains an IP address then this should be used as
+the basis of choosing a network. When there is no address in this attribute it
+can be assumed that the packet has been received from a client on the local
+LAN.
+
+The `files` module in FreeRADIUS provides a simple method to map
+`DHCP-Network-Subnet` to the corresponding pool based on its network
+membership, setting the appropriate options to return to clients. It can also
+set the global options.
+
+[TIP]
+====
+In the case where an instance of the `files` module is used to get global
+default parameters, the `dhcp_common` policy becomes redundant so the
+statement calling the policy (by name) can be commented out in
+`<raddb>/sites-enabled/dhcp`.
+====
+
+To use the provided example `files` module instance for DHCP, symlink or copy
+`<raddb>/mods-available/dhcp_files` into `<raddb>/mods-enabled/` and then
+uncomment the calls to `dhcp_network` in `<raddb>/sites-enabled/dhcp`.
+
+A template configuration file `<raddb>/mods-config/files/dhcp` is also
+provided which should be adapted to suit your network topology.
+
+For the configuration above you may deduce the following configuration, which
+has been extended to include an initial default section for requests originating
+from directly-connected clients on the local LAN (192.168.20/24):
+
+[source,config]
+----
+network Pool-Name := "local"
+ DHCP-Domain-Name := "example.org",
+ DHCP-Subnet-Mask := 255.255.255.0,
+ DHCP-Router-Address := 192.168.20.1,
+ DHCP-Domain-Name-Server := 192.168.20.2,
+ Fall-Through := yes
+
+network DHCP-Network-Subnet < 10.10.0.0/16, Pool-Name := "remote"
+ DHCP-Subnet-Mask := 255.0.0.0,
+ DHCP-Router-Address := 10.10.0.1,
+ DHCP-Domain-Name-Server := 10.10.0.2,
+ DHCP-Domain-Name-Server += 10.10.0.3,
+ DHCP-IP-Address-Lease-Time := 7200
+----
+
+Each block in the file starts with a line beginning with the key to be matched.
+In this case the keyword of `network` (defined earlier in `dhcp_networks`
+configuration) is used for each block, so each of the above blocks is a
+candidate during the search.
+
+There may be further filtering of the candidates in the form of `<Attribute>
+<op> <Value>`. In the case of the second block we match the
+`DHCP-Network-Subnet` to an enclosing subnet with
+`DHCP-Network-Subnet < <subnet>`. Additional filters could be added as
+required, comma separated.
+
+Following the filters on the first line, attributes in the `control` list can
+be set using the syntax of `<Attribute> := <Value>`. In this example this is
+used to specify the `Pool-Name` for choosing the appropriate IP pool to
+allocate an address from.
+
+Subsequent indented lines are attribute assignments for values in the `reply`
+list. Note that, apart from the last line, they are all terminated with a
+comma.
+
+The special option `Fall-Through` determines whether, following a match,
+other records are checked for a match. All lookups will match the entry
+with a key of `network` and no further filtering, so `Fall-Through`
+is set on that record in order that the other records will be tested
+to find subnet matches.
+
+=== Example packet processing
+
+For our example, we consider a request arriving from a DHCP relay within
+10.10.0.0/16. In the absence of any specific DHCP subnet selection options in
+the request, the `DHCP-Network-Subnet` attribute is calculated to be the
+relay's IP address, say 10.10.0.1.
+
+The request is matched against the first block, setting an initial pool name to
+"local", domain name to "example.org" and setting some additional global
+default parameters. By virtue of `Fall-Through` being set, the next block is
+considered.
+
+Since the network identifier is within the specified subnet (i.e. `10.10.0.1 <
+10.10.0.0/16`) this second block is matched. This block overrides the pool name
+setting it to "remote", overrides some other global defaults and sets the lease
+time to 7200 seconds. `Fall-Through` is not set, so we are now done with
+deriving the pool name and network options.
+
+When the `dhcp_sqlippool` module is called during DHCP DISCOVER processing (in
+`<raddb>/sites-enabled/dhcp`) the `remote` pool will be used for IP address
+allocation.
+
+The assigned IP address and network parameters will subsequently be returned in
+the DHCP reply.
+
+=== Testing the pool operation and network-specific options
+
+Before proceeding further, you should test the operation of the IP pools and
+ensure that any network-specific reply attributes that you have configured are
+correctly set in replies.
+
+For example, if you have a single, flat pool you should test using sample
+packets for devices with different MAC addresses and/or Client Identifiers.
+
+[source,shell]
+----
+cat <<EOF > dhcp-packet-1.txt
+DHCP-Message-Type := DHCP-Discover
+DHCP-Client-Hardware-Address := 02:01:11:11:11:11
+DHCP-Client-Identifier := device1
+EOF
+----
+
+[source,shell]
+----
+cat <<EOF > dhcp-packet-2.txt
+DHCP-Message-Type := DHCP-Discover
+DHCP-Client-Hardware-Address := 02:01:22:22:22:22
+DHCP-Client-Identifier := device2
+EOF
+----
+
+Generate these packets as show previously using the dhcpclient tool and look
+for `DHCP-Your-IP-Address` in the DHCP responses to determine the IP address
+that has been offered.
+
+Ensure that the DHCP Offer responses contain unique IP addresses. Ensure that
+when these requests are resent within the lifetime of the initial offer that
+the reponses to the subsequent replies contain the original IP address that was
+in the initial offer to the device.
+
+Additionally, ensure that the DHCP Offers contain any network-specific
+parameters that you have specified.
+
+In the case that the policy contains multiple IP pools and network definitions
+for clients belonging to different Layer 2 networks (or indeed belonging to the
+same network but segregated according to some local policy) you should ensure
+that the devices are being mapped to the correct definition.
+
+For a typical policy that selects the IP pool and network options based on the
+originating network for the DHCP packet, explicitly specifying a network by
+including a `DHCP-Subnet-Selection-Option` parameter may avoid the need to test
+from a host within each individual network:
+
+[source,shell]
+----
+cat <<EOF > dhcp-packet-network-10.10.10.0.txt
+DHCP-Message-Type := DHCP-Discover
+DHCP-Client-Hardware-Address := 02:01:aa:bb:cc:dd
+DHCP-Client-Identifier := abc123
+DHCP-Subnet-Selection-Option := 10.10.10.0
+EOF
+----
+
+For policies where the IP pool and network option selection is based on some
+custom criteria it is necessary to include different variations for the
+parameters on which the policy makes the decision. The testing example for the
+class-specific options later in this document provides such an example.
--- /dev/null
+== Configure subnet-specific options for shared networks
+
+In the case that shared-networks are in use, with the pool containing
+equally-valid IP addresses from multiple subnets, it is necessary to set the
+subnet-specific parameters such as `DHCP-Router-Address`, `DHCP-Subnet-Mask`
+and `DHCP-Broadcast-Address` based on the IP address that has been allocated.
+
+Consider the ISC DHCP configuration snippet:
+
+[source,iscdhcp]
+----
+option domain-name "example.org";
+
+shared-network bigdept {
+
+ option domain-name-servers 10.10.0.2, 10.10.0.3;
+ default-lease-time 7200;
+
+ subnet 10.30.10.0 netmask 255.255.255.0 {
+ option routers 10.30.10.1;
+ }
+ subnet 10.30.20.0 netmask 255.255.255.0 {
+ option routers 10.30.20.1;
+ }
+ range 10.30.10.10 10.30.10.254;
+ range 10.30.20.10 10.30.20.254;
+
+}
+----
+
+Or the equivalent Kea configuration:
+
+[source,kea]
+----
+"Dhcp4": {
+ "option-data": [
+ { "name": "domain-name", "data": "example.org" }
+ ],
+ "shared-networks": [{
+ "name": "bigdept",
+ "option-data": [
+ { "name": "domain-name-servers", "data": "10.10.0.2, 10.10.0.3" }
+ ],
+ "valid-lifetime": 7200,
+ "subnet4": [{
+ "subnet": "10.30.10.0/24",
+ "pools": [ { "pool": "10.30.10.10 - 10.30.10.254" } ],
+ "option-data": [
+ { "name": "routers", "data": "10.30.10.1" }
+ ]
+ }],
+ "subnet4": [{
+ "subnet": "10.30.20.0/24",
+ "pools": [ { "pool": "10.30.20.10 - 10.30.20.254" } ],
+ "option-data": [
+ { "name": "routers", "data": "10.30.20.1" }
+ ]
+ }]
+ }],
+ ...
+}
+----
+
+As with the network to pool lookup, an instance of the `files` modules can be
+employed (this time after the allocation of an IP address) to set the correct
+reply parameters based on the subnet membership of the assigned address.
+
+To do this, we can use this section of `<raddb>/mods-available/dhcp_files`:
+
+[source,config]
+----
+files dhcp_subnets {
+ filename = ${modconfdir}/files/dhcp
+ key = "subnet"
+}
+----
+
+Additionally, uncomment the `dhcp_subnets` policy in `<raddb>/policy.d/dhcp`.
+This policy wraps the call to the `dhcp_subnets` files module with code that
+"tightens" the `DHCP-Network-Subnet` attribute by setting it to the
+just-allocated IP address.
+
+The relevant entries in the `<raddb>/mods-config/files/dhcp` configuration
+file might then look something like this:
+
+[source,config]
+----
+network
+ DHCP-Domain-Name := "example.org",
+ Fall-Through := yes
+
+network DHCP-Network-Subnet < 10.30.0.0/16, Pool-Name := "bigdept"
+ DHCP-Domain-Name-Server := 10.10.0.2,
+ DHCP-Domain-Name-Server += 10.10.0.3,
+ DHCP-IP-Address-Lease-Time := 7200
+
+subnet DHCP-Network-Subnet < 10.30.10.0/24
+ DHCP-Router-Address := 10.30.10.1
+
+subnet DHCP-Network-Subnet < 10.30.20.0/24
+ DHCP-Router-Address := 10.30.20.1
+----
+
+=== Example packet processing
+
+For our example, we consider a request arriving from a DHCP relay within
+10.30.10.0/24. In the absence of any specific DHCP subnet selection options in
+the request, the `DHCP-Network-Subnet` attribute is calculated to be the
+relay's IP address, say 10.30.10.1.
+
+The request is matched against the first "network" block, setting the domain
+name to "example.org". By virtue of `Fall-Through` being set, the next "network"
+block is considered.
+
+Since the network identifier is within the specified subnet (i.e. `10.30.10.1 <
+10.30.0.0/16`) this second "network" block is matched. This block sets the pool
+name to "bigdept", sets some network-specific DNS resolvers and sets the lease
+time to 7200 seconds. `Fall-Through` is not set, so we are now done with
+deriving the pool name and network options.
+
+When the `dhcp_sqlippool` module is called during DHCP DISCOVER processing (in
+`<raddb>/sites-enabled/dhcp`) the `bigdept` pool will be used for IP address
+allocation.
+
+After IP allocation the `dhcp_subnet` policy and files instance are called.
+Before the subnet options are looked up the `DHCP-Network-Subnet`
+attribute is tightened to match the assigned IP address, say 10.30.20.123.
+
+The request does not match the first subnet block since 10.30.20.123 is not
+within 10.30.10.0/24. However, the request does match the second subnet block
+since `10.30.20.123 < 10.30.20.0/24`. This block sets the default gateway
+reply parameter. `Fall-Through` is not set, so we are now done with deriving
+the pool name and network options.
+
+The assigned IP address, network and subnet parameters will subsequently be
+returned in the DHCP reply.
+
+=== Testing the subnet-specific options
+
+If you have set any subnet-specific reply parameters then you should test these
+before proceeding further.
+
+For example, in the case that you have a single, large pool spanning two IP
+subnets you might want to test by repeatedly allocating addresses using sample
+packets with different MAC addresses, each time checking to ensure that the
+DHCP parameters correspond to the IP address that has been offered.
+
+.Example output from dhcpclient showing a response
+==================================================
+ dhcpclient: ...
+ ...
+ ----------------------------------------------------------------------
+ Waiting for DHCP replies for: 5.000000
+ ----------------------------------------------------------------------
+ ...
+ DHCP-Your-IP-Address = 10.0.10.50
+ DHCP-Router-Address = 10.0.10.1
+ DHCP-Broadcast-Address = 10.0.10.255
+ DHCP-Subnet-Mask = 255.255.255.255
+==================================================
+
+
+.Example output from dhcpclient showing a response
+==================================================
+ dhcpclient: ...
+ ...
+ ----------------------------------------------------------------------
+ Waiting for DHCP replies for: 5.000000
+ ----------------------------------------------------------------------
+ ...
+ DHCP-Your-IP-Address = 10.99.99.50
+ DHCP-Router-Address = 10.99.99.1
+ DHCP-Broadcast-Address = 10.99.99.255
+ DHCP-Subnet-Mask = 255.255.255.255
+==================================================
+
+
+[TIP]
+====
+If the subnets are large then you might want to temporarily reduce their
+size by setting the `status` field of the majority of the rows for each subnet
+to "`disabled`" to cause offers to be made more readily with IP addresses in
+different subnets.
+====
--- /dev/null
+== Preparation
+
+It is necessary to consider the requirements for the installation in order to
+devise an efficient and manageable set up.
+
+=== Understand the network topology
+
+When multiple networks (VLANs) are in use consideration must be given to how
+the correct "pool" (IP address ranges) from which to allocate addresses is
+identified.
+
+The policy for setting specific DHCP options (e.g. lease time, default gateway,
+time server and vendor-specific parameters) for different groups of hosts,
+based on their network or some device attributes either supplied in the DHCP
+requests or determined by dynamic lookup, should be well defined and
+understood.
+
+Other DHCP servers may implement implicit assumptions about the requirement of
+your network topology and silently define particular behaviours, such as the
+selection of IP address pool for a request based on a relay address. Some of
+these behaviours must be specifed explicitly when using FreeRADIUS.
+
+=== Choose a database backend
+
+FreeRADIUS stores its leases in an SQL database, so one of the key decisions to
+make is which database to use.
+
+FreeRADIUS supports:
+
+ * SQLite
+ * PostgreSQL
+ * MySQL / MariaDB
+ * Microsoft SQL Server
+ * Oracle
+
+In most configurations the SQL database is likely to be the limiting component
+that restricts the IP allocation throughput of the overall system. Each
+database server has its own performance characteristics and unique approach to
+features such as high-availability.
+
+The choice of database should be made carefully based on the performance and
+high-availability requirements of the system, as well as any prior experience.
+
+[TIP]
+====
+SQLite is an in-process database that uses the local file system, is simple to
+configure and is suitable for smaller installations. However, users with larger
+address pools or high availability requirements should choose one of the other
+standalone databases based on criteria such as performance, features,
+familiarity and your need for commercial support.
+====
+
+FreeRADIUS ships with a default database schema and set of queries for each
+supported database. These are sufficient for most DHCP deployments but can be
+reviewed and modified as required to suit a particular situation, for example
+to customise the IP allocation policy such as by disabling address
+"stickiness".
+
+Now xref:protocols/dhcp/enable.adoc[enable the DHCP service].
--- /dev/null
+== Testing the DHCP service
+
+We can verify that FreeRADIUS is providing a DHCP service using the
+`dhcpclient` tool that is included with the FreeRADIUS distribution.
+
+Temporarily configure FreeRADIUS to issue a single static IP address to all
+clients by updating the `dhcp DHCP-Discover` section in the `dhcp` virtual
+server to include the following:
+
+[source,unlang]
+----
+update reply {
+ &DHCP-Your-IP-Address := 1.2.3.4
+}
+----
+
+Define a sample DHCP packet as follows:
+
+[source,shell]
+----
+cat <<EOF > dhcp-packet.txt
+DHCP-Message-Type := DHCP-Discover
+DHCP-Client-Hardware-Address := 02:01:aa:bb:cc:dd
+DHCP-Client-Identifier := abc123
+EOF
+----
+
+We can now generate this packet by invoking one of the following commands based
+on the current circumstances...
+
+From the host that is running the FreeRADIUS DHCP server:
+
+[source,shell]
+----
+dhcpclient -i lo 255.255.255.255 -f dhcp-packet.txt -x auto
+----
+
+From a different host with an interface (eth0) in the same broadcast domain
+as the FreeRADIUS DHCP server:
+
+[source,shell]
+----
+dhcpclient -i eth0 255.255.255.255 -f dhcp-packet.txt -x auto
+----
+
+If all of the DHCP broadcast traffic in other Layer 2 networks is converted to
+unicast by DHCP relay agents then it is not necessary for FreeRADIUS to listen
+on a broadcast address. In this case you can test DHCP using a unicast request:
+
+[source,shell]
+----
+dhcpclient 192.0.2.10 -f dhcp-packet.txt -x auto
+----
+
+[NOTE]
+====
+In order for the returned, unicast DHCP OFFER to be received it is necessary to
+ensure that the `DHCP-Your-IP-Address` parameter set by FreeRADIUS matches an
+address on the interface used by the dhcpclient tool to send the Discover
+packet.
+====
+
+When one of the above commands is run, the tool with generate output such as
+the following which shows that the packet was sent and that it is now waiting
+for replies:
+
+.Example output from dhcpclient showing the request
+===================================================
+ dhcpclient: ...
+ ----------------------------------------------------------------------
+ DHCP-Opcode = 0x01
+ DHCP-Hardware-Type = 0x01
+ DHCP-Hardware-Address-Length = 0x06
+ DHCP-Hop-Count = 0x00
+ DHCP-Transaction-Id = 0x5e0bbfab
+ DHCP-Number-of-Seconds = 0x0000
+ DHCP-Flags = 0x0000
+ DHCP-Client-IP-Address = 0x00000000
+ DHCP-Your-IP-Address = 0x00000000
+ DHCP-Server-IP-Address = 0x00000000
+ DHCP-Gateway-IP-Address = 0x00000000
+ ...
+ ----------------------------------------------------------------------
+ Waiting for DHCP replies for: 5.000000
+ ----------------------------------------------------------------------
+===================================================
+
+
+Each received DHCP response will generate output such as the following:
+
+.Example output from dhcpclient showing a response
+==================================================
+ ...
+ ----------------------------------------------------------------------
+ DHCP-Opcode = Server-Message
+ DHCP-Hardware-Type = Ethernet
+ DHCP-Hardware-Address-Length = 6
+ DHCP-Hop-Count = 0
+ DHCP-Transaction-Id = 1577828267
+ DHCP-Number-of-Seconds = 0
+ DHCP-Flags = 0
+ DHCP-Client-IP-Address = 0.0.0.0
+ DHCP-Your-IP-Address = 1.2.3.4
+ DHCP-Server-IP-Address = 192.0.2.10
+ DHCP-Gateway-IP-Address = 0.0.0.0
+ DHCP-Client-Hardware-Address = 02:42:0a:00:00:0b
+ DHCP-Message-Type = DHCP-Offer
+ DHCP-Client-Identifier = 0x616263313233
+ Waiting for additional DHCP replies for: 4.999429
+ ...
+==================================================
+
+Examine the DHCP response to ensure that it has the correct message type
+(`DHCP-Offer`, in this case), contains the temporary IP address that you
+configured earlier, i.e. `DHCP-Your-IP-Address = 1.2.3.4`, and any other
+expected reply parameters (which we configure later). You should also carefully
+examine the output of a FreeRADIUS debug session (`radius -X`) to ensure that
+the policy is being executed in the way that you expect and that no warnings
+are being generated.
+
+You can now change the content of the sample DHCP request by editing the
+`dhcp-packet.txt` file and re-run the above command to see the server's reply.
+You should examine the DHCP dictionary distrubuted with FreeRADIUS (usually
+`/usr/share/freeradius/dictionary.dhcp`) which provides the list of all of the
+DHCP parameters ("attributes") understood by FreeRADIUS.
+
+[WARNING]
+====
+When you are done **remember** to remove the temporary edit that was made to
+the `dhcp` virtual server that provides the static IP assignment.
+====
+
+=== Testing the DHCP policy
+
+The remainder of this guide describes how to configure the IP address plan,
+setup the IP pools and define a DHCP policy. You should develop your policy by
+making small, incremental changes to the provided configuration and then test
+those changes with the approach described above, using `dhcpclient` and `radius -X`,
+modifying the sample DHCP packet as required. If you break the policy then
+revert the last change, attempt to understand what went wrong, and try
+something else.
+
+Now xref:protocols/dhcp/policy.adoc[define the DHCP policy].
--- /dev/null
+== Enabling PROXY Protocol
+
+Now that we have a working configuration which used RadSec and HAproxy
+or Traefik, we are finally ready to enable PROXY Protocol.
+
+Configure FreeRADIUS on the `radsecsvr` host to expect the PROXY
+Protocol for RadSec connections. This is done by editing the `listen
+{}` section of the `tls` virtual server to include a reference to the
+proxy protocol:
+
+.Enabling PROXY Protocol in a FreeRADIUS virtual server
+=======================================================
+
+ listen {
+ ...
+ proxy_protocol = true
+ ...
+ }
+
+=======================================================
+
+Now restart the debugging session:
+[source,shell]
+----
+radiusd -fxxl /dev/stdout
+----
+
+
+For HAproxy, you should enable the PROXY Protocol on connections to
+the RadSec backend, by editing the `backend` definition to add a
+`send-proxy` argument:
+
+.Example HAproxy backend configuration with PROXY Protocol
+==========================================================
+
+ backend radsec_be
+ mode tcp
+ balance roundrobin
+ server radsecsvr 172.23.0.3:2083 send-proxy
+
+==========================================================
+
+Note the `send-proxy` argument in the `server` definition.
+
+Now reload the HAproxy service:
+
+[source,shell]
+----
+service haproxy reload
+----
+
+
+For Traefik, enable the PROXY Protocol on connections to the RadSec
+backend by editing the `radsec-service` definition to add a reference
+to the proxy protocol"
+
+.Example Traefik service configuration with PROXY Protocol
+==========================================================
+
+ radsec-service:
+ loadBalancer:
+ servers:
+ - address: "172.23.0.3:2083"
+ proxyProtocol:
+ version: 1
+
+==========================================================
+
+Note the `proxyProtocol` and `version: 1` directives.
+
+Traefik should automatically detect the updates and reconfigure the
+service.
+
+
+=== Testing RadSec connectivity via a proxy using PROXY Protocol
+
+Finally, with your test client configured to use the proxy, perform a
+test authentication:
+
+[source,shell]
+----
+echo "User-Name = bob" | radclient 127.0.0.1 auth testing123
+----
+
+You should expect to see the familiar output:
+
+.Example output from radclient
+==============================
+
+ Sent Access-Request Id 252 from 0.0.0.0:50118 to 127.0.0.1:1812 length 27
+ Received Access-Accept Id 252 from 127.0.0.1:1812 to 127.0.0.1:50118 length 39
+
+==============================
+
+Now examine the FreeRADIUS debug output on the RadSec server:
+
+.Expected output from `radiusd -X` with PROXY Protocol
+======================================================
+
+ ...
+ (0) (TLS) Received PROXY protocol connection from client \
+ 172.23.0.2:55343 -> 172.23.0.4:2083, via proxy 172.23.0.4:40268 -> 0.0.0.0:2083
+ ...
+ (0) Received Access-Request Id 227 from 172.23.0.2:55343 to 172.23.0.4:2083 length 49
+ (0) Sent Access-Accept Id 227 from 172.23.0.4:2083 to 172.23.0.2:55343 length 0
+ ...
+
+======================================================
+
+The output indicates that FreeRADIUS is receiving the originating
+connection information from the PROXY Protocol. FreeRADIUS then
+handles the RadSec requests as though they have been received directly
+from the originating client.
+
--- /dev/null
+== Enabling RadSec with FreeRADIUS
+
+Our first task is to set up a RadSec server by configuring an instance of
+FreeRADIUS to accept RADIUS over TLS requests.
+
+The following steps should be performed on the host which will be the
+RadSec server, we will call it `radsecsvr`.
+
+You can install FreeRADIUS using the NetworkRADIUS packages by
+following the instructions provided here:
+
+<https://networkradius.com/packages/>
+
+Before making any configuration changes, you should stop the radiusd
+service:
+
+[source,shell]
+----
+ service radiusd stop
+----
+
+Then, enable the `tls` virtual server:
+
+[source,shell]
+----
+cd /etc/raddb/sites-enabled
+ln -s ../sites-available/tls
+----
+
+The FreeRADIUS distribution contains an example Certificate Authority
+that will have generated the necessary CA, server and client
+certificates and keys during package installation. You can use this
+CA, or you can use your own CA and certificates.
+
+[TIP]
+====
+If the example certificates are not present (for example if FreeRADIUS was
+installed from source) then FreeRADIUS will fail to start. The files can be
+regenerated by running `make` in the `/etc/raddb/certs` directory.
+====
+
+Edit the `tls` virtual server configuration, in order to add
+definitions for the clients by extending the `clients radsec {}` section:
+
+.Example radsec client definitions in `/etc/raddb/sites-available/tls`
+====
+
+ clients radsec {
+ ...
+ # Direct connections from the test client
+ client radseccli {
+ ipaddr = 172.23.0.2
+ proto = tls
+ virtual_server = default
+ }
+ # Connections via HAproxy
+ client haproxy {
+ ipaddr = 172.23.0.4
+ proto = tls
+ virtual_server = default
+ }
+ # Connections via Traefik
+ client traefik {
+ ipaddr = 172.23.0.5
+ proto = tls
+ virtual_server = default
+ }
+ }
+
+====
+
+The client `ipaddr` configuration item is used to match the source IP
+address of incoming connections. You must add client definitions for
+each of the clients which will connect.
+
+For RadSec, you can just list the IP address of the RadSec client.
+This client definition is used for processing RADIUS packets from the
+RadSec client.
+
+[NOTE]
+====
+A `secret` does not have to be specified for RadSec clients, as the
+default is `radsec`. If you specify a secret, then that will be used
+instead of `radsec`.
+====
+
+When the PROXY protocol is used, you must _also_ define a client which
+matches the IP address of the proxy (haproxy, etc). This client is
+only used to check that the source IP is permitted to connect to the
+server. Fields other than `ipaddr` can be specified (and in some
+cases may be required). However, all other fields will be ignored.
+
+For testing purposes, we want to amend the `default` virtual server so
+that it accepts all authentication reqeusts and immediately responds
+to accounting requests.
+
+Edit the `/etc/raddb/sites-enabled/default` file so that the beginning of
+the `authorize` and `preacct` sections looks as follows:
+
+.Example default virtual server modification to unconditionally accept Access-Requests
+====
+
+ authorize {
+ accept
+ ...
+ }
+ ...
+ preacct {
+ handled
+ ...
+ }
+
+====
+
+This change makes the `authorize` section always "accept" the user,
+and makes the `preacct` section always say "we handled the accounting
+request". These changes are only for testing, and should never be
+used in production.
+
+Start the FreeRADIUS service in the foreground with debugging enabled:
+
+[source,shell]
+----
+radiusd -fxxl /dev/stdout
+----
+
+Examine the output from FreeRADIUS to ensure that it is now listening for
+RadSec connection on TCP/2083:
+
+.Example output from running `radiusd -fxxl /dev/stdout`
+====
+
+ FreeRADIUS Version 3.0.24
+ Copyright (C) 1999-2021 The FreeRADIUS server project and contributors
+ ...
+ ... : Debug: Listening on auth+acct proto tcp address * port 2083 (TLS) bound to server default
+ ... : Debug: Listening on auth address * port 1812 bound to server default
+ ... : Debug: Listening on acct address * port 1813 bound to server default
+ ... : Debug: Listening on auth address :: port 1812 bound to server default
+ ... : Debug: Listening on acct address :: port 1813 bound to server default
+ ...
+ ... : Info: Ready to process requests
+
+====
+
+FreeRADIUS is now ready to process RadSec traffic.
+
+For testing, we first test normal RADIUS over UDP functionality, then
+the RadSec connection using a test client, then introduce a proxy
+server, and finally we enable PROXY Protocol. Doing the tests in this
+way ensures that we know that all previous steps work before trying
+the next step. This process allows us to quickly narrow down
+problems, and gets us to the final goal _faster_ than just "doing
+everything all at once".
+
+=== Testing the RADIUS policy
+
+Before moving on, verify that the FreeRADIUS policy is able to
+authenticate a local test RADIUS Access-Request over UDP:
+
+[source,shell]
+----
+echo "User-Name = terry" | radclient 127.0.0.1 auth testing123
+----
+
+Due to the `accept` we added in the `authorize` section, the expected
+output should be an Access-Accept:
+
+.Expected output from radclient
+===============================
+
+ Sent Access-Request Id 157 from 0.0.0.0:36850 to 127.0.0.1:1812 length 27
+ Received Access-Accept Id 157 from 127.0.0.1:1812 to 127.0.0.1:36850 length 20
+
+===============================
+
+Any other output indicates that there is a problem with the FreeRADIUS
+configuration which *must* be solved before testing RadSec. Carefully verify that
+you have carried out each of the above steps correctly and examine the debug
+output from FreeRADIUS, which will usually tell you what is wrong.
+
+See [how to read the debug
+output](http://wiki.freeradius.org/radiusd-X) for instructions on
+reading amd understanding the debug output.
+
+The next step is to xref:protocols/proxy/radsec_client.adoc[configure
+FreeRADIUS as a RadSec test client] so that we can verify that our
+RadSec server is working.
--- /dev/null
+= Proxying RadSec and enabling PROXY Protocol
+
+This guide shows how to set up FreeRADIUS to serve RadSec connections, fronted
+by either HAproxy or Traefik as Layer 4 proxies that pass on the original
+client connection information using PROXY Protocol.
+
+It is not a comprehensive guide to using RadSec with FreeRADIUS. It presents a
+basic configuration that uses an example CA and does not validate certificate
+attributes or perform revokation status.
+
+
+== Introduction
+
+FreeRADIUS supports receiving RADIUS requests over TLS-enabled TCP connections
+and supports proxying of requests over TCP connections to another TLS-enabled
+homeserver. The protocol for RADIUS over TLS is called "RadSec" and is defined
+in RFC 6614.
+
+FreeRADIUS is a capable and performant application-aware ("Layer 7") proxy /
+load-balancer for RadSec and other forms of RADIUS traffic.
+
+
+=== Layer 4 proxying
+
+Rather than use an application-aware proxy it is sometimes better to reduce the
+performance impact incurred by re-encoding an application protocol by using a
+"Layer 4" proxy that operates at the level of individual connections without
+regard for the application protocol. Such a proxy is more of a "bump in the
+wire" than a request buffer and minimises the latency incurred due to proxying.
+
+It is common to see software such as HAproxy and Traefik used in Layer 4 mode
+in place of FreeRADIUS for purposes such as connection load balancing. In
+addition to improved performance, these tools have the benefit that they
+typically support dynamic service discovery and "hitless" reloads to
+automatically adapt their connection routing based on changes to backend
+services such as the introduction of new nodes with even a momentary loss of
+service.
+
+
+=== Loss of connection information
+
+When TCP connections are relayed through Layer 4 proxies the information
+about the originating source of the connection is no longer known to the
+backend service, unless it is otherwise made available. Identifying the
+originator of connections is often necessary for security purposes and for
+request processing.
+
+Whilst many application protcols support headers that allow proxies to preserve
+connection information these are not helpful in the context of Layer 4
+proxying: The process of populating headers requires knowledge of the
+application protocol to re-encode requests as they are transmitted between the
+frontend and backend connections.
+
+
+=== PROXY Protocol
+
+PROXY Protocol overcomes this limitation by allowing the original connection
+information to be provided to the backend at the start of the TCP connection.
+After this initial data is encoded the remainder of the conversation then
+proceeds as normal. However now that the connection information is known to the
+backend server it is able to process requests made on the connection as though
+the connection were being made directly by the client and not via the proxy.
+
+PROXY Protocol is specified in this document:
+http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
+
+
+== Requirements
+
+PROXY Protocol Version 1 is supported by FreeRADIUS v3.0.24 and later versions.
+
+You will require the following set of VMs or containers, each with their own
+IP address:
+
+[cols="1,1,1"]
+|===
+|Hostname|IP address|Purpose
+
+|radseccli
+|172.23.0.2
+|FreeRADIUS configured to provide a RadSec test client
+
+|radsecsvr
+|172.23.0.3
+|FreeRADIUS configured as a RadSec server
+
+|haproxy
+|172.23.0.4
+|HAproxy in Layer 4 mode to the FreeRADIUS RadSec backend
+|===
+
+Optionally you may want to configure a host to run Traefik within a Docker
+container using host mode networking, perhaps configured by Docker Compose,
+however the installation is beyond the scope of this guide:
+
+[cols="1,1,1"]
+|===
+|traefik
+|172.23.0.5
+|Traefik configured as a TCP router with TLS passthrough to the FreeRADIUS RadSec backend
+|===
+
+The hostnames and IP addresses provided above are for examples purposes and are
+used throughout the remainder of this guide. This guide provides commands and
+output for CentOS. Other distributions will have minor differences, including
+the location of the FreeRADIUS configuration (the "raddb").
+
+[NOTE]
+====
+You can choose to use your own hostname, IP addresses and OS distribution. You
+could also use official Docker images provided by the respecitive projects,
+however these prescribe methods for configuring and managing the services
+that are not typical for a normal package installation which would provide a
+distraction if used for by guide.
+====
+
+
+== Sections in this guide
+
+This guide is organised into four parts that should be read in order:
+
+1. xref:protocols/proxy/enable_radsec.adoc[Enabling RadSec]
+2. xref:protocols/proxy/radsec_client.adoc[Configuring a test RadSec client]
+3. xref:protocols/proxy/radsec_with_haproxy.adoc[Proxying RadSec with HAproxy]
+4. xref:protocols/proxy/radsec_with_traefik.adoc[Proxying RadSec with Traefik]
+5. xref:protocols/proxy/enable_proxy_protocol.adoc[Enabling PROXY Protocol for RadSec]
--- /dev/null
+== Configuring FreeRADIUS as a RadSec test client
+
+Unfortunately, the `radclient` program does not support RadSec. We
+must therefore configure an instance of FreeRADIUS as a "transport
+converter" which proxies UDP-based RADIUS requests to a RadSec
+destination of our choice.
+
+The following steps should be performed on a client system, which we
+will call `radseccli`. This system should be a new system, with a
+different IP address. That is, you shoudl not edit the configuration
+on the `radsecsvr` host. Doing so will break the RadSec configuration.
+
+Install FreeRADIUS using the NetworkRADIUS packages by following the
+instructions provided here:
+
+<https://networkradius.com/packages/>
+
+Before making any configuration changes, you should stop the radiusd
+service:
+
+[source,shell]
+----
+ service radiusd stop
+----
+
+Add a new `tls` home server definition, which will point to the RadSec
+server. We do this by creating a file
+`/etc/raddb/sites-enabled/radsec-homeserver` with the following
+contents:
+
+.Example homeserver, pool and realm definitions for the RadSec service
+====
+
+ home_server tls {
+ ipaddr = 172.23.0.3 # IP address of our RadSec server
+ port = 2083
+ type = auth+acct
+ proto = tcp
+ tls {
+ private_key_password = whatever
+ private_key_file = ${certdir}/client.pem
+ certificate_file = ${certdir}/client.pem
+ ca_file = ${cadir}/ca.pem
+ }
+ }
+ home_server_pool tls {
+ type = fail-over
+ home_server = tls
+ }
+ realm tls {
+ auth_pool = tls
+ acct_pool = tls
+ }
+
+====
+
+[TIP]
+====
+Complete descriptions of each of the above configuration items can be found in the
+`[raddb]/sites-available/tls` example configuration file. For simple tests, however,
+we can omit all of the comments from the file.
+====
+
+To use this `tls` home server, we change the `default` virtual server to proxy
+all authentication and accounting requests to it.
+
+Edit the `/etc/raddb/sites-enabled/default` file so that the beginning of
+the `authorize` and `preacct` sections looks as follows:
+
+.Example default virtual server modification to proxy requests to a RadSec proxy server
+====
+
+ authorize {
+ update control {
+ &Proxy-To-Realm := tls
+ }
+ handled
+ ...
+ }
+ ...
+ preacct {
+ update control {
+ &Proxy-To-Realm := tls
+ }
+ handled
+ ...
+ }
+
+====
+
+These changes make the `tls` virtual server always proxy packets.
+These changes are only for testing, and should never be used in
+production.
+
+We must now copy the example CA certificate as well as the client
+certificate and key files which are on the `radsecsrv` host to this
+test client.
+
+Replace the following files on `radseccli` with the equivalent files from
+`radsecsrv`:
+
+[cols="1,1,1"]
+|===
+|File|Corresponding configuration item|Purpose
+
+|/etc/raddb/certs/ca.pem
+|`ca_file`
+|CA certificate which is used to authenticate the server certificate presented by the RadSec server to the client.
+
+|/etc/raddb/certs/client.pem
+|`certificate_file`
+|Client certificate (signed by the CA certificate) that is presented by the test client to the RadSec server.
+
+|/etc/raddb/certs/client.pem
+|`private_key_file` and `private_key_password`
+|Private key corresponding to the client certificate
+|===
+
+Note that the client certificate and key are typically bundled into a single file.
+
+[CAUTION]
+====
+If you do not correctly replace the CA, client certificate, and key
+material on the test client then the RadSec client and RadSec server
+will fail to mutually authenticate each other as they do not share a
+trusted CA. If you see messages like `unknown CA`, then you know that
+the certificates have not been set up correctly.
+====
+
+Start the FreeRADIUS service in debug mode:
+
+[source,shell]
+----
+radiusd -X
+----
+
+
+=== Testing RadSec connectivity
+
+At this stage you should be able to cause the test client to send RadSec
+requests directly to the RadSec server.
+
+Run the following to send a RADUS (UDP) Access-Request to the local FreeRADIUS
+instance. It should then proxy the request over RadSec connection to
+the remote RadSec server:
+
+[source,shell]
+----
+ echo "User-Name = bob" | radclient 127.0.0.1 auth testing123
+----
+
+If the test client is able to successfully establish the RadSec
+connection, and the RadSec server replies with an Access-Accept
+response, then the output will be as follows:
+
+.Expected output from radclient
+===============================
+
+ Sent Access-Request Id 252 from 0.0.0.0:50118 to 127.0.0.1:1812 length 27
+ Received Access-Accept Id 252 from 127.0.0.1:1812 to 127.0.0.1:50118 length 39
+
+===============================
+
+Lack of response or an Access-Reject response indicates that the RadSec
+connection is not being established successfully.
+
+There may be serveral reasons for broken connectivity including:
+
+ * The client not accepting the certificate presented by the server.
+ * The server not accepting the certificate presented by the client.
+
+Look at the debug output generated by both the test client and the RadSec
+server. In many cases it will tell you exactly what the problem is.
+
+Do not proceed with any further steps until direct connections between the
+RadSec client and Radsec Server are working properly.
+
+Once things are working we are ready to
+xref:protocols/proxy/radsec_with_haproxy.adoc[configure HAproxy to proxy RadSec
+connections] or to xref:protocols/proxy/radsec_with_traefik.adoc[configure
+Traefik to proxy RadSec connections].
--- /dev/null
+== Proxying RadSec with HAproxy
+
+This section shows how to configure HAproxy to proxy RadSec connections.
+
+The following steps should be performed on the `haproxy` host, unless otherwise
+stated.
+
+Install the HAproxy package supplied with the OS distribution:
+
+[source,shell]
+----
+ yum install haproxy
+----
+
+Stop the haproxy service:
+
+[source,shell]
+----
+ service haproxy stop
+----
+
+Modify the haproxy configuration (typically `/etc/haproxy/haproxy.conf`) so
+that it includes new frontend and backend configuration for the radsec service:
+
+.Example minimal HAproxy configuration
+======================================
+
+ global
+ maxconn 100
+ defaults
+ mode tcp
+ timeout connect 10s
+ timeout client 30s
+ timeout server 30s
+ frontend radsec_fe
+ bind *:2083
+ default_backend radsec_be
+ backend radsec_be
+ balance roundrobin
+ server radsecsvr 172.23.0.3:2083
+
+======================================
+
+Note the `mode tcp` directive which tells HAproxy to act as a Layer 4
+proxy, so that it doesn't attempt to perform SSL termination or
+decode the RADIUS protocol.
+
+[NOTE]
+====
+The above example is a minimal configuration. In practise you will want to
+retain many of the HAproxy configuration items already present in the
+configuration (e.g. `log`, `chroot`, `user`, `group`), but these vary across
+distributions. Other HTTP-related options that may already exist in the
+configuration will conflict with `mode tcp` (Layer 4 proxying) and should be
+removed if HAproxy complains about them.
+
+However, you should first get things working with the minimal
+configuration which is known to work, and then make customisations.
+If you start off with a complex configuration, then there may be a
+large number of things which are broken, and debugging them all will
+be difficult. Start simple, and then add complexity!
+====
+
+Restart the haproxy service in foreground mode for debugging purposes:
+
+[source,shell]
+----
+haproxy -f /etc/haproxy/haproxy.cfg -db
+----
+
+
+=== Testing RadSec connectivity via HAproxy
+
+Now edit the test RadSec client, so that instead of making connections directly
+to the RadSec server it makes connections to the HAproxy server.
+
+On `radseccli` edit the `/etc/raddb/sites-enabled/tls` file, and set
+the IP address to the address of the `haproxy` host.
+
+.Example updated test client homeserver configuration
+=====================================================
+
+ home_server tls {
+ ipaddr = 172.23.0.4 # Updated from radsecsvr to haproxy
+ ...
+ }
+
+=====================================================
+
+Restart the debug mode session:
+
+[source,shell]
+----
+radiusd -X
+----
+
+Perform a test authentication:
+
+[source,shell]
+----
+ echo "User-Name = bob" | radclient 127.0.0.1 auth testing123
+----
+
+If the test client is able to successfully establish the RadSec
+connection via HAproxy, and the RadSec server replies with an
+Access-Accept response, then the output will be as follows:
+
+.Expected output from radclient
+===============================
+
+ Sent Access-Request Id 252 from 0.0.0.0:50118 to 127.0.0.1:1812 length 27
+ Received Access-Accept Id 252 from 127.0.0.1:1812 to 127.0.0.1:50118 length 39
+
+===============================
+
+HAproxy should also log a message that indicates that the connection was
+proxied, such as the following:
+
+.Expected output from HAproxy
+=============================
+
+ <150>...: Connect from 172.23.0.2:50087 to 172.23.0.4:2083 (radius_fr/TCP)
+
+=============================
+
+Any other output from radclient or HAproxy indicates that there is a
+problem with the HAproxy configuration, or that FreeRADIUS is not
+accepting connection from the `haproxy` host, which must be solved
+before continuing.
+
+Once proxied connections are working we are ready to
+xref:protocols/proxy/enable_proxy_protocol.adoc[enable the PROXY
+Protocol] on both HAproxy and the RadSec server.
+
--- /dev/null
+== Proxying RadSec with Traefik
+
+This section shows how to configure Traefik to proxy RadSec connections. You
+should skip this section if you are not using Traefik as your proxy.
+
+Installing Traefik is beyond the scope of this guide. It is typically installed
+as a service mesh router within a Docker or Kubernetes environment using
+offical Docker images.
+
+Traefik configuration has two components of interest:
+
+ * Static configuration: Defines "entrypoints" on which Traefik listens for connections.
+ * Dynamic configuration: Defines backend service components and the routing policy.
+
+Traefik supports a number of providers of dynamic configuration data for the
+router and service definitions. For demonstration purposes the files provider
+is used here, however you can switch to another provide once you have things
+working using this method.
+
+The static configuration can be provided by starting Traefik with the following
+arguments:
+
+.Example Traefik static configuration
+=====================================
+
+ traefik \
+ --log.level=DEBUG \
+ --providers.file.filename=/etc/traefik/dynamic_config.yml
+ --providers.file.watch=true
+ --entryPoints.radsec.address=:2083
+
+=====================================
+
+Note that a `radsec` entrypoint is defined to listen on port 2083 and that a
+static `file` provider is used to defined the dynamic services.
+
+The backend for RadSec should be defined in this file as follows:
+
+.Example Traefik dynamic configuration
+======================================
+
+ tcp:
+ routers:
+ radsec-router:
+ entryPoints:
+ - radsec
+ rule: "HostSNI(`*`)"
+ service: "radsec-service"
+ tls:
+ passthrough: true
+ services:
+ radsec-service:
+ loadBalancer:
+ servers:
+ - address: "172.23.0.3:2083"
+
+======================================
+
+Note the `passthrough: true` directive under `tls:` which tells Treafik not to
+attempt TLS termination which it would otherwise perform for all incoming TLS
+connections. We require that the connection is passed through from the RadSec
+client to the RadSec server without being reterminated since the end client's
+certificate is authenticated by the RadSec server and many be used for
+policy decisions.
+
+
+=== Testing RadSec connectivity via Traefik
+
+Now amend the test RadSec client so that instead of making connections directly
+to the RadSec server it makes them via Traefik.
+
+On `radseccli` amend `/etc/raddb/sites-enabled/tls` and set the IP address to
+that of the `traefik` host.
+
+.Example updated test client homeserver configuration
+=====================================================
+
+ home_server tls {
+ ipaddr = 172.23.0.5 # Updated from radsecsvr to traefik
+ ...
+ }
+
+=====================================================
+
+Restart the debug mode session:
+
+[source,shell]
+----
+radiusd -X
+----
+
+Perform a test authentication:
+
+[source,shell]
+----
+ echo "User-Name = bob" | radclient 127.0.0.1 auth testing123
+----
+
+If the test client is able to successfully establish the RadSec connection via
+Traefik and the RadSec server replies with an Access-Accept response then the
+output will be as follows:
+
+.Example output from radclient
+==============================
+
+ Sent Access-Request Id 252 from 0.0.0.0:50118 to 127.0.0.1:1812 length 27
+ Received Access-Accept Id 252 from 127.0.0.1:1812 to 127.0.0.1:50118 length 39
+
+==============================
+
+Traefik should also log a message that indicates that the connection was
+proxied, such as the following:
+
+.Example output from Traefik
+============================
+
+ time="..." level=debug msg="Handling connection from 172.23.0.2:57367"
+
+============================
+
+Any other output from radclient or Traefik indicates that there is a problem
+with the Traefik configuration or that FreeRADIUS is not accepting connection
+from the `traefik` host, which must be solved before continuing.
+
+Once proxied connections are working we are ready to
+xref:protocols/proxy/enable_proxy_protocol.adoc[enable the PROXY Protocol] on
+both Traefik and the RadSec server.
+