summaryrefslogtreecommitdiffstats
path: root/doc/antora/modules
diff options
context:
space:
mode:
Diffstat (limited to 'doc/antora/modules')
-rw-r--r--doc/antora/modules/concepts/nav.adoc6
-rw-r--r--doc/antora/modules/concepts/pages/aaa.adoc60
-rw-r--r--doc/antora/modules/concepts/pages/index.adoc8
-rw-r--r--doc/antora/modules/concepts/pages/modules/ldap/authentication.adoc203
-rw-r--r--doc/antora/modules/developers/nav.adoc7
-rw-r--r--doc/antora/modules/developers/pages/bugs.adoc194
-rw-r--r--doc/antora/modules/developers/pages/coding-methods.adoc235
-rw-r--r--doc/antora/modules/developers/pages/contributing.adoc126
-rw-r--r--doc/antora/modules/developers/pages/coverage.adoc11
-rw-r--r--doc/antora/modules/developers/pages/index.adoc18
-rw-r--r--doc/antora/modules/developers/pages/profile.adoc41
-rw-r--r--doc/antora/modules/developers/pages/release-method.adoc55
-rw-r--r--doc/antora/modules/howto/nav.adoc3
-rw-r--r--doc/antora/modules/howto/pages/monitoring/index.adoc67
-rw-r--r--doc/antora/modules/howto/pages/monitoring/statistics.adoc336
-rw-r--r--doc/antora/modules/howto/pages/protocols/dhcp/policy_common_options.adoc2
-rw-r--r--doc/antora/modules/howto/pages/protocols/proxy/enable_proxy_protocol.adoc4
-rw-r--r--doc/antora/modules/howto/pages/simultaneous_use.adoc78
-rw-r--r--doc/antora/modules/installation/pages/dependencies.adoc31
-rw-r--r--doc/antora/modules/unlang/nav.adoc2
-rw-r--r--doc/antora/modules/unlang/pages/case.adoc2
-rw-r--r--doc/antora/modules/unlang/pages/condition/index.adoc2
-rw-r--r--doc/antora/modules/unlang/pages/condition/operands.adoc2
-rw-r--r--doc/antora/modules/unlang/pages/default.adoc2
-rw-r--r--doc/antora/modules/unlang/pages/type/index.adoc6
-rw-r--r--doc/antora/modules/unlang/pages/xlat/builtin.adoc2
26 files changed, 1464 insertions, 39 deletions
diff --git a/doc/antora/modules/concepts/nav.adoc b/doc/antora/modules/concepts/nav.adoc
new file mode 100644
index 0000000..493b956
--- /dev/null
+++ b/doc/antora/modules/concepts/nav.adoc
@@ -0,0 +1,6 @@
+* xref:index.adoc[Concepts]
+** General
+*** xref:aaa.adoc[AAA]
+** Modules
+*** LDAP
+**** xref:modules/ldap/authentication.adoc[Authentication]
diff --git a/doc/antora/modules/concepts/pages/aaa.adoc b/doc/antora/modules/concepts/pages/aaa.adoc
new file mode 100644
index 0000000..294305c
--- /dev/null
+++ b/doc/antora/modules/concepts/pages/aaa.adoc
@@ -0,0 +1,60 @@
+= AAA
+
+== Authorization, Authentication, and Accounting request handling
+
+There are a lot of questions about misconfigured FreeRADIUS servers
+because of misunderstanding of FreeRADIUS operations. This document
+explains how the server operates.
+
+Normally there are two steps in processing an authentication request
+coming from a NAS in FreeRADIUS: authorization and authentication.
+If we use FreeRADIUS as a proxy to re-send the request to another
+RADIUS server there will be additional steps.
+
+=== Authorization
+
+Authorization is the process of finding and returning information
+about what the user is allowed to do. For example, finding out what
+kind of authentication methods they are allowed to run, and what VLAN
+the user should be placed into.
+
+Authorization modules generally "get data" from somewhere,
+e.g. `ldap`, `sql`, `files`, etc.
+
+The authentication method is usually determined when the server gets
+the users credentials from a database. Once the credentials are
+available, the server can authenticate the user.
+
+=== Authentication
+
+Authentication is simply a process of comparing user’s credentials in
+request with the "known good" credentials retrieved from a
+database. Authentication usually deals with password
+encryption. The modules `pap`, `chap`, `mschap`, etc. do authentication.
+
+Some modules do both authentication and limited authorization. For
+example, the `mschap` module authenticates MS-CHAP credentials, but it
+may also be used as an authorization module, which verifies that
+request contains `MS-CHAP` related attribute. If so, the module
+instructs the server to use `mschap` for authentication, too
+
+These dual modules are usually related to protocol-specific
+attributes, such as the `pap` module for the `User-Password`
+attribute, `chap` for `CHAP-Password`, `mschap` for `MS-CHAP-*`, etc.
+
+=== Request Processing
+
+When the server processes requests, it manages four
+xref:unlang:list.adoc[attribute lists]:
+
+`request`:: attributes taken from the received packet
+
+`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 restroed across multiple request / reply exchanges.
+
+All of these lists are available to all modules. All of these
+lists are available in xref:unlang:index.adoc[Unlang].
+
diff --git a/doc/antora/modules/concepts/pages/index.adoc b/doc/antora/modules/concepts/pages/index.adoc
new file mode 100644
index 0000000..f2bc25f
--- /dev/null
+++ b/doc/antora/modules/concepts/pages/index.adoc
@@ -0,0 +1,8 @@
+= Concepts
+
+This section documents concerning the protocols and modules used by the
+FreeRADIUS server.
+
+It intended to provide more theoretical information about particular subjects
+than would be appropriate to include inline in module configurations or as
+sidebars in howto guides.
diff --git a/doc/antora/modules/concepts/pages/modules/ldap/authentication.adoc b/doc/antora/modules/concepts/pages/modules/ldap/authentication.adoc
new file mode 100644
index 0000000..edc553e
--- /dev/null
+++ b/doc/antora/modules/concepts/pages/modules/ldap/authentication.adoc
@@ -0,0 +1,203 @@
+== Authenticating Users with LDAP
+
+Please be aware the FreeRADIUS is an AAA server, and LDAP
+is a _database_. This separation of roles means that FreeRADIUS
+supports multiple kinds of authentication protocols such as `PAP`,
+`CHAP`, `MS-CHAP`, etc. An LDAP database supports only one
+authentication method: "bind as user". This authentication method is
+compatible only with PAP.
+
+Our recommendation is to use LDAP as a database. FreeRADIUS should
+read the "known good" password from LDAP, and then use that
+information to authenticate the user. It is almost always wrong to
+use the LDAP "bind as user" method for authenticating users.
+
+The only caveat to the above recommendation is Active Directory. For
+"security" reasons, Active Directory will not return the "known good"
+password to FreeRADIUS over a standard LDAP query. Therefore when
+Active Directory is used, the choices are:
+
+PAP::
+Use "bind as user"
+
+MS-CHAP::
+Use xref:raddb:mods-available/ntlm_auth.adoc[`ntlm`] or xref:raddb:mods-available/winbind.adoc[`winbind`].
+
+Due to the limitations of Active Directory, There are unfortunately no
+other possible choices.
+
+== LDAP Security Recommendations
+
+The credentials (username *and* password) for FreeRADIUS to use to
+connect to your LDAP server(s) should be secure. We make the
+following recommendations for LDAP "best practices" security.
+
+* Create a dedicated account for use by FreeRADIUS
+
+* Ensure that this account does not have administrator access
+
+* Ensure that this account is read-only, and has no write permissions
+
+* Start by using 'simple authentication' instead of
+ https://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer[SASL].
+ The SASL protocol should be attempted only after 'simple
+ authentication' has been verified to work.
+
+* Use TLS for connecting between FreeRADIUS and the LDAP server. See
+ the `tls` sub-section of the default `ldap` module for instructions
+
+* When storing RADIUS user profiles (quotas, `Simultaneous-Use` flags,
+ access time restrictions, etc) in LDAP, the LDAP schema
+ `doc/schemas/ldap/openldap/freeradius-radius.schema` must first be imported
+ into the LDAP server.
+
+== Authentication method compatibility
+
+The LDAP module is compatible a few different kinds of authentication
+methods. Note that we say _compatible_, and not _supports_. LDAP
+servers are databases, and do not support authentication protocols
+such as CHAP, MS-CHAP, or EAP.
+
+PAP::
+The user supplies a `User-Password` (plaintext or EAP-TTLS/PAP)
++
+FreeRADIUS reads the "known good" password from LDAP, and compares
+that to what the user entered.
+
+Bind as user::
+The user supplies a `User-Password` (plaintext or EAP-TTLS/PAP)
++
+FreeRADIUS uses that password to "bind as the user" to LDAP, using the
+supplied `User-Name` and `User-Password. If the bind is successfull,
+the user is authenticated. Otherwise, authentication fails.
+
+CHAP::
+The user supplies a `CHAP` password attribute.
++
+FreeRADIUS reads the "known good" password from LDAP in cleartext, and
+compares that to what the user entered.
+
+MS-CHAP::
+The user supplies a `MS-CHAP` password attribute. Either as
+MS-CHAPv2, or as PEAP/MSCHAPv2, or as EAP-TTLS/MS-CHAPv2.
++
+FreeRADIUS reads the "known good" password from LDAP in cleartext, or
+as an NT hash, and compares that to what the user entered.
+
+All of above authentication methods other than "bind as user" require
+that FreeRADIUS obtain the `userPassword` field from LDAP. If that
+field is not returned to FreeRADIUS, then normal authentication is
+impossible. Either FreeRADIUS has to be configured to use "bind as
+user" for authentication, or the LDAP database has to be updated to
+return the `userPassword` field to FreeRADIUS. This change usually
+involves giving the FreeRADIUS "read-only" user permission to read the
+`userPassword` field.
+
+Again, the best method is to test authentication is with the
+xref:howto:modules/ldap/ldapsearch/index.adoc[ldapsearch] tool.
+These tests *must* be run prior to configuring FreeRADIUS. We strongly
+recommend having the LDAP database return the `userPassword` field to
+FreeRADIUS, so that FreeRADIUS can authenticate the user.
+
+We also strongly recommend that the passwords be stored in LDAP as
+cleartext. Otherwise, the only authentication methods that will work
+are PAP and EAP-TTLS/PAP. The next section explains these issues in
+more detail.
+
+== Password Storage Methods
+
+If the `userPassword` field is returned from LDAP to FreeRADIUS, that
+information can be stored in a number of different formats:
+
+* the value can be cleartext
+* the value can be prepended with a string enclosed by braces, such as with `{crypt}` or `{ssha3}`.
+* the value can be have a suffix of `::`, in which case the password is generally a https://en.wikipedia.org/wiki/Base64[base64] encoded version of the real password
+
+TIP: Base64 values can be decoded via the command: `printf "%s"
+"VALUE" | base64 -d`
+
+FreeRADIUS is capable of understanding and parsing all of the above
+formats. There is sufficient information in the password values to
+determine what format it is in (base64, binary, or text), and what
+password "encryption" mechanism has been used (crypt, MD5, SHA, SSHA2,
+SHA3, etc). All that is necessary is that the
+xref:raddb:mods-available/ldap.adoc[ldap module] be configured to map
+the `userPassword` LDAP field to the `&control.Password.With-Header`
+attribute in FreeRADIUS. FreeRADIUS will then "do the right thing" to
+authenticate the user.
+
+This mapping is done in the default module configuration. There are
+no additional changes required for FreeRADIUS to correctly read and
+decode the `userPassword` field from LDAP. Please see the
+xref:raddb:mods-available/pap.adoc[pap module] for a full list of
+supported password "encryption" formats.
+
+== Additional Considerations
+
+There are some major caveats with the above authentication methods.
+The first is that we *strongly recommend* against using "bind as
+user". This process is slow, and causes unnecessary churn in the
+connections used to contact the LDAP server. Further, the "bind as
+user" process works _only_ when a `User-Password attribute exists in
+the request. If any other authentication type is used in the request,
+then the "bind as user" _will not work_. There is no amount of
+"fixing" things or configuration changes which will make it work.
+
+The second caveat is that the `CHAP` authentication type works _only_
+when a "clear text" password is stored in the LDAP database. The
+`CHAP` calclulations are designed around having access to the "clear
+text" password. It is impossible to use any "encrypted" or "hashed"
+passwords with `CHAP`.
+
+The third caveat is that the `MS-CHAP` authentication type works
+_only_ when a "clear text" password or "NT hashed" passwords which are
+stored in the LDAP database. The `MS-CHAP` calculations are designed
+around having access to "known good" passwords in those formats. It
+is impossible to use any other kind of "encrypted" or "hashed"
+passwords with `MS-CHAP`.
+
+The final caveat is that when the LDAP database contains "encrypted"
+or "hashed" passwords, the _only_ authentication type which is
+compatible with those passwords is PAP. i.e. when the `User-Password`
+is supplied to FreeRADIUS.
+
+For recommendations on password storage methods in LDAP, please see
+the LDAP
+https://openldap.org/doc/admin24/security.html#Password%20Storage[password
+storage] page. Please note that the recommendations there are made
+for LDAP security, and pay no attention to the caveats described
+above. When both RADIUS and LDAP are used together, then the
+requirements of _both_ systems must be met in order for them to work
+together. In many cases, a naive approach to LDAP security will
+prevent RADIUS from working.
+
+The issue of a database storing passwords in clear-text has to be
+balanced against the users sending clear-text passwords in
+authentication protocols. While those passwords are protected by TLS
+(EAP-TTLS) or by RADIUS (in it's own "encryption" mechanism), it is
+generally better to use a stronger authentication method than just
+PAP.
+
+In the end, there is no perfect solution to security requirements.
+The choice may be either to give up on using a particular
+authentication method, or to relax the security requirements on LDAP
+and on password storage. The final decision as to which choice is
+best can only be made by a local administrator.
+
+== Integrating Novell eDirectory with FreeRADIUS
+
+You can integrate Novell eDirectoryTM 8.7.1 or later with FreeRADIUS
+1.0.2 onwards to allow wireless authentication for eDirectory users. By
+integrating eDirectory with FreeRADIUS, you can do the following:
+
+* Use universal password for RADIUS authentication. Universal password
+provides single login and authentication for eDirectory users.
+Therefore, the users need not have a separate password for RADIUS and
+eDirectory authentication.
+* Enforce eDirectory account policies for users. The existing eDirectory
+policies on the user accounts can still be applied even after
+integrating with RADIUS. Also, you can make use of the intruder lockout
+facility of eDirectory by logging the failed logins into eDirectory.
+
+For configuration information please refer to the Novell documentation
+https://www.netiq.com/documentation/edir_radius/
diff --git a/doc/antora/modules/developers/nav.adoc b/doc/antora/modules/developers/nav.adoc
new file mode 100644
index 0000000..ed6962a
--- /dev/null
+++ b/doc/antora/modules/developers/nav.adoc
@@ -0,0 +1,7 @@
+* xref:index.adoc[Developers]
+** xref:bugs.adoc[Bugs]
+** xref:coding-methods.adoc[Coding Methods]
+** xref:coverage.adoc[Code Coverage]
+** xref:profile.adoc[Profiling]
+** xref:contributing.adoc[Contributing]
+** xref:release-method.adoc[Release Method]
diff --git a/doc/antora/modules/developers/pages/bugs.adoc b/doc/antora/modules/developers/pages/bugs.adoc
new file mode 100644
index 0000000..b63329c
--- /dev/null
+++ b/doc/antora/modules/developers/pages/bugs.adoc
@@ -0,0 +1,194 @@
+= Bugs
+
+== Introduction
+
+The FreeRADIUS web site is at https://freeradius.org/, and most
+information referenced in this document can be found there.
+
+This document is primarily for non-developers of the FreeRADIUS
+server. If you are able to patch the code to work correctly, then
+we invite you to join the development list to discuss it. If
+you’re the type who know little about how to code, then this is
+the place for you!
+
+== You found a bug
+
+Where the server terminates ungracefully due to a bus error,
+segmentation violation, or other memory error, you should create a new
+issue in the issue tracker https://bugs.freeradius.org/, including
+information from the debugging sections below.
+
+For any other issues, you should first discuss them on the
+https://freeradius.org/support/[FreeRADIUS users list], to
+see if anyone can reproduce them. Often there’s a simple explanation of
+why the server behaves as it does, and it’s not necessarily a bug in the
+code, so browse the lists’ archives of the last two months, and if you
+don’t see messages about it, ask!
+
+If the behavior is correct but confusing, we think that’s a bug too, and
+you should file a bug against our documentation.
+
+For more information about the users list, the lists’ archives and the
+faq, please visit https://www.freeradius.org/list/users.html Please make
+sure to READ and RESPECT the house-rules. You will get much better
+response and much faster if you do!
+
+== Core dumps
+
+If the server (or one of the accompanying programs) core dumps, then you
+should rebuild the server as follows:
+
+```
+$ ./configure --enable-developer
+$ make
+$ make install
+```
+
+and then run the program again. You may have to to enable core dumps,
+via:
+
+```
+$ ulimit -c unlimited
+```
+
+When it core dumps, do:
+
+```
+$ gdb /path/to/executable /path/to/core/file
+```
+
+Enable logging in `gdb` via the following commands:
+
+```
+(gdb) set logging file gdb-radiusd.log
+(gdb) set logging on
+```
+
+and follow the instructions in the proceeding section.
+
+You can also enable the `panic_action` given in
+`raddb/radiusd.conf`. See the comments in that file for more details
+about automatically collecting gdb debugging information when the server
+crashes.
+
+== Debugging a live server
+
+If you can’t get a core dump, or the problem doesn’t result in a core
+dump, you may have to run the server under gdb. To do this, ensure that
+you have symbols in the binaries (i.e. a 'non-stripped' binary) by
+re-building the server as described in the previous section. Then, run
+the server under gdb as follows:
+
+```
+$ gdb radiusd
+```
+
+Enable logging in `gdb` via the following commands:
+
+```
+(gdb) set logging file gdb-radiusd.log
+(gdb) set logging on
+```
+
+Tell `gdb` to pass any necessary command-line arguments to the server:
+
+```
+(gdb) set args ...
+```
+
+Where the ``…'' are the command-line arguments you normally pass to
+radiusd. For debugging, you probably want to do:
+
+```
+(gdb) set args -fxx
+```
+
+Then, do:
+
+```
+(gdb) run
+```
+
+When something interesting happens, you can hit CTRL-C in the window,
+and you should be back at the gdb prompt:
+
+```
+(gdb)
+```
+
+And follow the instructions in the next section.
+
+== Obtaining useful information
+
+Once you have a core dump loaded into gdb, or FreeRADIUS running under
+gdb, you may use the commands below to get useful information about the
+state of the server.
+
+If the server was built with threads, you can do:
+
+```
+(gdb) info threads
+```
+
+Which will give you information about the threads. If the server isn’t
+threaded, that command-line will print a message saying so.
+
+Then, do:
+
+```
+(gdb) thread apply all bt full
+```
+
+If the server isn’t threaded, the `thread apply` section isn’t
+necessary
+
+The output should be printed to the screen, and also sent to the
+`gdb-radiusd.log` file.
+
+You should then submit the information from the log file, along with any
+server output, the output of `radiusd -xv`, and information about your
+operating system to:
+
+https://bugs.freeradius.org/
+
+Submitting it to the bug database ensures that the bug report won’t get
+forgotten, and that it will be dealt with in due course.
+
+You should provide the issue number in any mail sent to the user’s list.
+
+== Valgrind
+
+On Linux systems, `valgrind` is a useful tool that can catch certain
+classes of bugs. To use it, run the server via:
+
+```
+$ valgrind --tool=memcheck --leak-check=full radiusd -Xm
+```
+
+It will print out certain kinds of errors to the screen. There may be a
+number of errors related to OpenSSL, dlopen(), or libtldl. We cannot do
+anything about those problems. However, any errors that are inside of
+the FreeRADIUS source should be brought to our attention.
+
+== Running with `screen`
+
+If the bug is a crash of the server, and it takes a long time for the
+crash to happen, perform the following steps:
+
+* Log in as root.
+* Open a https://www.gnu.org/software/screen/[screen] session: `$ screen bash`.
+* Make sure FreeRADIUS is not running.
+* Make sure you have all the debug symbols about, or a debugable version
+of the server installed (one built with `--enable-developer` as above).
+* Configure screen to log to a file by pressing `Ctrl+a`, then `h`.
+* Type `gdb /path/to/radiusd` (or /path/to/freeradius on Debian).
+* At the `(gdb)` prompt, type `run -X`.
+* Detach from screen with `Ctrl+a`, `d`.
+* When you notice FreeRADIUS has died, reconnect to your screen session
+`$ screen -D -r`.
+* At the `(gdb)` prompt type `where` or for _lots_ of info try
+`thread apply all bt full`.
+* Tell screen to stop logging, `Ctrl+a`, `h`.
+* Logout from screen.
+
+FreeRADIUS Project, copyright 2019
diff --git a/doc/antora/modules/developers/pages/coding-methods.adoc b/doc/antora/modules/developers/pages/coding-methods.adoc
new file mode 100644
index 0000000..3de92c4
--- /dev/null
+++ b/doc/antora/modules/developers/pages/coding-methods.adoc
@@ -0,0 +1,235 @@
+= Coding Methods
+
+The following is a short set of guidelines to follow while programming. It does
+not address coding styles, function naming methods, or debugging methods.
+Rather, it describes the processes which should go on in the programmer’s mind
+while they are programming.
+
+Coding standards apply to function names, the look of the code, and coding
+consistency. Coding methods apply to the daily practices used by the programmer
+to write code.
+
+== Comment your code
+
+If you don’t, you’ll be forced to debug it six months later, when you have no clue
+as to what it’s doing.
+
+If someone _really_ hates you, you’ll be forced to debug un-commented code that
+someone else wrote. You don’t want to do that.
+
+For FreeRADIUS, use doxygen `@`-style comments so you get the
+benefits of the developer documentation site, https://doc.freeradius.org/.
+
+== Give things reasonable names
+
+Variables and functions should have names. Calling them `x`, `xx`,
+and `xxx` makes your life hell. Even `foo` and `i` are
+problematic.
+
+Avoid smurfs. Don’t re-use struct names in field names, i. e.
+
+[source,c]
+----
+struct smurf {
+ char *smurf_pappa_smurf;
+}
+----
+
+If your code reads as full English sentences, you’re doing it right.
+
+== Check input parameters in the functions you write
+
+Your function _cannot_ do anything right if the user passed in garbage
+and you were too lazy to check for garbage input.
+
+`assert()` (`fr_assert()`) is ugly. Use it.
+
+[NOTE]
+====
+GIGO, "Garbage In, Garbage Out," is wrong. If your function gets
+garbage input, it should complain loudly and with great
+descriptiveness.
+====
+
+== Write useful error messages
+
+"Function failed" is useless as an error message. It makes debugging the code
+impossible without source-level instrumentation.
+
+If you’re going to instrument the code at source level for error messages, leave
+the error messages there, so the next sucker won’t have to do the same work all
+over again.
+
+== Check error conditions from the functions you call
+
+Your function _cannot_ do anything right if you called another function, and
+they gave you garbage output.
+
+One of the most common mistakes is:
+
+[source,c]
+----
+fp = fopen(...);
+fgetc(fp); /* core dumps! */
+----
+
+If the programmer had bothered to check for a `NULL` fp (error
+condition), then they could have produced a descriptive error message
+instead of having the program core dump.
+
+== Core dumps are for weenies
+
+If your program core dumps accidentally, you’re a bad programmer. You don’t know
+what your program is doing, or what it’s supposed to be doing when anything goes
+wrong.
+
+If it hits an `assert()` and calls `abort()`, you’re a genius. You’ve thought
+ahead to what _might_ go wrong, and put in an assertion to ensure that it fails
+in a _known manner_ when something _does_ go wrong. (As it usually does…)
+
+== Initialize your variables
+
+`memset()` (`talloc_zero()`) is your friend. `ptr = NULL` is nice,
+too.
+
+Having variables containing garbage values makes it easy for the code to do
+garbage things. The contents of local variables are inputs to your function. See
+xref:#_check_input_parameters_in_the_functions_you_write[#3].
+
+It’s also nearly impossible for you to debug any problems, as you can’t tell the
+variables with garbage values from the real ones.
+
+== Don’t allow buffer over-runs
+
+They’re usually accidental, but they cause core dumps. `strcpy()` and `strcat()`
+are ugly. Use them under duress.
+
+`sizeof()` is your friend.
+
+== `const` is your friend
+
+If you don’t mean to modify an input structure to your function, declare it
+`const`. Declare string constants `const`. It can’t hurt, and it allows more
+errors to be found at compile time.
+
+Use `const` everywhere. Once you throw a few into your code, and have it save
+you from stupid bugs, you’ll blindly throw in `const` everywhere. It’s a
+life-saver.
+
+== Use C compiler warnings
+
+Turn on all of the C compiler warnings possible. You might have to turn some off
+due to broken system header files, though. But the more warnings the merrier.
+
+Getting error messages at compile time is much preferable to getting core dumps
+at run time. See xref:#_initialize_your_variables[#7].
+
+Notice that the C compiler error messages are helpful? You should write error
+messages like this, too. See xref:#_write_useful_error_messages[#4].
+
+== Avoid UNIXisms and ASCIIisms and visualisms
+
+You don’t know under what system someone will try to run your code. Don’t demand
+that others use the same OS or character set as you use.
+
+Never assign numbers to pointers. If foo is a `char*`, and you want it to be be
+`NULL`, assign `NULL`, not `0`. The zeroth location is perfectly as addressable
+as any other on plenty of OSes. Not all the world runs on Unix (though it should
+:) ).
+
+Another common mistake is to assume that the zeroth character in the character
+set is the string terminator. Instead of terminating a string with `0`, use
+`'\0'`, which is always right. Similarly, `memset()` with the appropriate value:
+`NULL`, `'\0'`, or `0` for pointers, chars, and numbers.
+
+Don’t put tabs in string constants, either. Always use `'\t'` to represent a
+tab, instead of ASCII 9. Literal tabs are presented to readers of your code as
+arbitrary whitespace, and it’s easy to mess up.
+
+== Make conditionals explicit
+
+Though it’s legal to test `if (foo) {}` if you test against the appropriate
+value (like `NULL` or `'\0'`), your code is prettier and easier for others to
+read without having to eyeball your prototypes continuously to figure out what
+you’re doing (especially if your variables aren’t well-named). See
+xref:#_give_things_reasonable_names[#2].
+
+== Test your code
+
+Even Donald Knuth writes buggy code. You’ll never find all of the bugs in your
+code. But writing a test program definitely helps.
+
+This means that you’ll have to write your code so that it will be easily
+testable. As a result, it will look better and be easier to debug.
+
+== Hints, Tips, and Tricks
+
+This section lists many of the common `rules` associated with code submitted to
+the project. There are always exceptions… but you must have a really good reason
+for doing so.
+
+== Read the Documentation and follow the CodingStyle
+
+The FreeRADIUS server has a common coding style. Use real tabs to indent. There
+is whitespace in variable assignments (`i = 1`, not `i=1`).
+
+When in doubt, format your code to look the same as code already in the server.
+If your code deviates too much from the current style, it is likely to be
+rejected without further review, and without comment.
+
+== #ifdefs are ugly
+
+Code cluttered with `#ifdef` s is difficult to read and maintain. Don’t do it.
+Instead, put your `#ifdef` s in a header, and conditionally define `static
+inline` functions, or macros, which are used in the code. Let the compiler
+optimize away the 'no-op' case.
+
+Simple example, of poor code:
+
+[source,c]
+----
+#ifdef CONFIG_MY_FUNKINESS
+ init_my_stuff(foo);
+#endif
+----
+
+Cleaned-up example:
+
+(in header):
+
+[source,c]
+----
+#ifndef CONFIG_MY_FUNKINESS
+ static inline void init_my_stuff(char *foo) {}
+#endif
+----
+
+(in the code itself):
+
+[source,c]
+----
+init_my_stuff(dev);
+----
+
+== `static inline` is better than a macro
+
+Static inline functions are greatly preferred over macros. They provide type
+safety, have no length limitations, no formatting limitations, and under gcc
+they are as cheap as macros.
+
+Macros should only be used for cases where a static inline is clearly suboptimal
+(there a few, isolated cases of this in fast paths), or where it is impossible
+to use a static inline function (such as string-izing).
+
+`static inline` is preferred over `$$static __inline__$$`, `extern inline`, and
+`$$extern __inline__$$`.
+
+== Don’t over-design
+
+Don’t try to anticipate nebulous future cases which may or may not be useful:
+_Make it as simple as you can, and no simpler._
+
+Split up functionality as much as possible. If your code needs to do two
+unrelated things, write two functions. Mashing two kinds of work into one
+function makes the server difficult to debug and maintain.
+
diff --git a/doc/antora/modules/developers/pages/contributing.adoc b/doc/antora/modules/developers/pages/contributing.adoc
new file mode 100644
index 0000000..e4a4b0a
--- /dev/null
+++ b/doc/antora/modules/developers/pages/contributing.adoc
@@ -0,0 +1,126 @@
+= Contributing
+
+== Submitting patches or diff’s to the FreeRADIUS project
+
+For a person or company wishing to submit a change to the FreeRADIUS
+project the process can sometimes be daunting if you’re not familiar
+with "the system." This text is a collection of suggestions which can
+greatly increase the chances of your change being accepted.
+
+Note: Only trivial patches will be accepted via email. Large patches, or
+patches that modify a number of files MUST be submitted as a
+https://github.com/FreeRADIUS/freeradius-server/pulls[pull-request via GitHub].
+
+== Hints and tips
+
+=== 1. Describe your changes
+
+Describe the technical detail of the change(s) your patch or commit
+includes.
+
+Be as specific as possible. The WORST descriptions possible include
+things like "update file X", "bug fix for file X", or "this patch
+includes updates for subsystem X. Please apply."
+
+If your description starts to get long, that’s a sign that you probably
+need to split up your commit. See the next point.
+
+=== 2. Separate your changes
+
+Separate each logical change into its own commit.
+
+For example, if your changes include both bug fixes and performance
+enhancements for a single module, separate those changes into two or
+more patches.
+
+On the other hand, if you make a single change to numerous files, group
+those changes into a single commit. Thus a single LOGICAL change is
+contained within a single commit.
+
+If one commit depends on another commit in order for a change to be
+complete, that is OK. Simply note "this commit depends on commit X" in
+the extended commit description.
+
+If your commit includes significant whitespace changes these should also
+be broken out into another, separate, commit.
+
+== Submitting patches via GitHub
+
+See the following links for more details about submitting via github:
+
+* https://help.github.com/articles/fork-a-repo
+* http://wiki.freeradius.org/contributing/GitHub
+
+== Submitting patches via email
+
+=== 1. diff -u
+
+Use `diff -u` or `diff -urN` to create patches.
+
+All changes to the source occur in the form of patches, as generated by
+diff(1). When creating your patch, make sure to create it in unified
+diff format, as supplied by the `-u` argument to diff(1). Patches
+should be based in the root source directory, not in any lower
+subdirectory.
+
+To create a patch for a single file, it is often sufficient to do::
+
+```
+SRCTREE=/home/user/src/freeradiusd/
+MYFILE=src/modules/rlm_foo/foo.c
+
+cd $SRCTREE
+cp $MYFILE $MYFILE.orig
+vi $MYFILE # make your change
+diff -u $MYFILE.orig $MYFILE > /tmp/patch
+```
+
+To create a patch for multiple files, you should unpack a `vanilla`,
+or unmodified source tree, and generate a diff against your own source
+tree. For example:
+
+```
+MYSRC=/home/user/src/freeradiusd-feature/
+
+gunzip freeradiusd-version.tar.gz
+tar xvf freeradiusd-version.tar
+diff -urN freeradiusd-version $MYSRC > ~/feature-version.patch
+```
+
+=== 2. Select e-mail destination
+
+If you are on the developers mailing list, send the patch there.
+mailto:freeradius-devel@lists.freeradius.org[freeradius-devel@lists.freeradius.org]
+
+Otherwise, send the patch to
+mailto:patches@freeradius.org[patches@freeradius.org]
+
+=== 3. No MIME, no links, no compression, no attachments. Just plain text
+
+The developers need to be able to read and comment on the changes you
+are submitting. It is important for a developer to be able to `quote`
+your changes, using standard e-mail tools, so that they may comment on
+specific portions of your code.
+
+For this reason, all patches should be submitting e-mail `inline`.
+
+Do not attach the patch as a MIME attachment, compressed or not. Many
+popular e-mail applications will not always transmit a MIME attachment
+as plain text, making it impossible to comment on your code. A MIME
+attachment also takes a bit more time to process, decreasing the
+likelihood of your MIME-attached change being accepted.
+
+Compressed patches are generally rejected outright. If the developer has
+to do additional work to read your patch, the odds are that it will be
+ignored completely.
+
+=== 4. E-mail size
+
+Large changes are not appropriate for mailing lists, and some
+maintainers. If your patch, exceeds 5Kb in size, you must submit the
+patch via GitHub instead.
+
+=== 5. Name the version of the server
+
+It is important to note, either in the subject line or in the patch
+description, the server version to which this patch applies.
diff --git a/doc/antora/modules/developers/pages/coverage.adoc b/doc/antora/modules/developers/pages/coverage.adoc
new file mode 100644
index 0000000..af6048e
--- /dev/null
+++ b/doc/antora/modules/developers/pages/coverage.adoc
@@ -0,0 +1,11 @@
+= Code Coverage
+
+We use the link:https://gcc.gnu.org/onlinedocs/gcc/Gcov-Intro.html#Gcov-Intro[gcov] tool to know our tests coverage.
+
+[source,shell]
+----
+$ make clean
+$ make coverage
+----
+
+If completed with success, a pretty report will be available in `${source_tree}/build/coverage/index.html`
diff --git a/doc/antora/modules/developers/pages/index.adoc b/doc/antora/modules/developers/pages/index.adoc
new file mode 100644
index 0000000..e66ef61
--- /dev/null
+++ b/doc/antora/modules/developers/pages/index.adoc
@@ -0,0 +1,18 @@
+= FreeRADIUS Development
+
+List with some usual howtos for FreeRADIUS.
+
+Programming reference documentation can be found at the
+https://doc.freeradius.org/[Doxygen] site.
+
+== Topics
+
+* xref:bugs.adoc[Bugs]
+* xref:coding-methods.adoc[Coding Methods]
+* xref:coverage.adoc[Code Coverage]
+* xref:profile.adoc[Profiling]
+* xref:contributing.adoc[Contributing]
+* xref:release-method.adoc[Release Method]
+
+Also see the xref:installation:dependencies.adoc[build
+dependencies] page.
diff --git a/doc/antora/modules/developers/pages/profile.adoc b/doc/antora/modules/developers/pages/profile.adoc
new file mode 100644
index 0000000..ca94f53
--- /dev/null
+++ b/doc/antora/modules/developers/pages/profile.adoc
@@ -0,0 +1,41 @@
+= Profiling
+
+Build with gperftools, and ensure that it's built:
+
+[source,shell]
+----
+$ grep profile Make.inc
+GPERFTOOLS_LIBS = -lprofiler
+----
+
+Run your test using the profiling tools. One signal will start the
+profiling, another will stop it.
+
+[source,shell]
+----
+env CPUPROFILE=/tmp/freeradius.prof CPUPROFILESIGNAL=12 freeradius ...
+killall -12 freeradius
+ ... wait ...
+killall -12 freeradius
+----
+
+View the results
+
+[source,shell]
+----
+pprof --text /path/to/freeradius /tmp/freeradius.prof
+----
+
+or as a graph
+
+[source,shell]
+----
+pprof --gv /path/to/freeradius /tmp/freeradius.prof
+----
+
+or as cachgrind output
+
+[source,shell]
+----
+pprof --cachegrind /path/to/freeradius /tmp/freeradius.prof
+----
diff --git a/doc/antora/modules/developers/pages/release-method.adoc b/doc/antora/modules/developers/pages/release-method.adoc
new file mode 100644
index 0000000..1de9e2d
--- /dev/null
+++ b/doc/antora/modules/developers/pages/release-method.adoc
@@ -0,0 +1,55 @@
+= Release Method
+
+== Topics
+
+[arabic]
+. As of 2.0, the release process is much simpler. Edit the Changelog
+with the version number and any last updates.
+
+```
+# vi doc/ChangeLog
+# git commit doc/ChangeLog
+```
+
+[arabic, start=2]
+. Change version numbers in the VERSION file:
+
+```
+# vi VERSION
+# git commit VERSION
+```
+
+[arabic, start=3]
+. Make the files
+
+NOTE: It also does `make dist-check`, which checks the build rules for
+various packages.
+
+```
+# make dist
+```
+
+[arabic, start=4]
+. Validate that the packages are OK. If so, tag the release.
+
+NOTE: This does NOT actually do the tagging! You will have to run the
+command it prints out yourself.
+
+```
+# make dist-tag
+```
+
+[arabic, start=5]
+. Sign the packages. You will need the correct GPG key for this to work.
+
+```
+# make dist-sign
+```
+
+[arabic, start=6]
+. Push to the FTP site. You will need write access to the FTP site for
+this to work.
+
+```
+# make dist-publish
+```
diff --git a/doc/antora/modules/howto/nav.adoc b/doc/antora/modules/howto/nav.adoc
index 351200b..dab23f8 100644
--- a/doc/antora/modules/howto/nav.adoc
+++ b/doc/antora/modules/howto/nav.adoc
@@ -17,3 +17,6 @@
***** xref:protocols/proxy/radsec_with_haproxy.adoc[Proxying RadSec with HAproxy]
***** xref:protocols/proxy/radsec_with_traefik.adoc[Proxying RadSec with Traefik]
***** xref:protocols/proxy/enable_proxy_protocol.adoc[Enabling PROXY Protocol for RadSec]
+** xref:monitoring/index.adoc[Monitoring]
+*** xref:monitoring/statistics.adoc[Server statistics]
+** xref:simultaneous_use.adoc[Simultaneous-Use]
diff --git a/doc/antora/modules/howto/pages/monitoring/index.adoc b/doc/antora/modules/howto/pages/monitoring/index.adoc
new file mode 100644
index 0000000..a08ffb4
--- /dev/null
+++ b/doc/antora/modules/howto/pages/monitoring/index.adoc
@@ -0,0 +1,67 @@
+= 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
diff --git a/doc/antora/modules/howto/pages/monitoring/statistics.adoc b/doc/antora/modules/howto/pages/monitoring/statistics.adoc
new file mode 100644
index 0000000..0583f0a
--- /dev/null
+++ b/doc/antora/modules/howto/pages/monitoring/statistics.adoc
@@ -0,0 +1,336 @@
+= 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
+----
diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/policy_common_options.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/policy_common_options.adoc
index 949868d..ca4d98f 100644
--- a/doc/antora/modules/howto/pages/protocols/dhcp/policy_common_options.adoc
+++ b/doc/antora/modules/howto/pages/protocols/dhcp/policy_common_options.adoc
@@ -1,6 +1,6 @@
== Configure common reply options
-FreeRADIUS includes a powerful xref:unlang/index.adoc[policy language] called
+FreeRADIUS includes a powerful xref:index.adoc[policy language] called
"unlang".
Statements in unlang may be used to call further policies, update attribute
diff --git a/doc/antora/modules/howto/pages/protocols/proxy/enable_proxy_protocol.adoc b/doc/antora/modules/howto/pages/protocols/proxy/enable_proxy_protocol.adoc
index b689824..a4ab3db 100644
--- a/doc/antora/modules/howto/pages/protocols/proxy/enable_proxy_protocol.adoc
+++ b/doc/antora/modules/howto/pages/protocols/proxy/enable_proxy_protocol.adoc
@@ -47,7 +47,7 @@ Now reload the HAproxy service:
[source,shell]
----
service haproxy reload
----
+----
For Traefik, enable the PROXY Protocol on connections to the RadSec
@@ -79,7 +79,7 @@ test authentication:
[source,shell]
----
- echo "User-Name = bob" | radclient 127.0.0.1 auth testing123
+echo "User-Name = bob" | radclient 127.0.0.1 auth testing123
----
You should expect to see the familiar output:
diff --git a/doc/antora/modules/howto/pages/simultaneous_use.adoc b/doc/antora/modules/howto/pages/simultaneous_use.adoc
new file mode 100644
index 0000000..b4a97ab
--- /dev/null
+++ b/doc/antora/modules/howto/pages/simultaneous_use.adoc
@@ -0,0 +1,78 @@
+= Simultaneous-Use checking
+
+There are a whole lot of pieces which have to work together for
+`Simultaneous-Use` to work. In this guide, we assume that user
+sessions are stored in SQL.
+
+For `Simultaneous-Use` to work. the server needs to know who is
+online, which means that accounting must be configured and working.
+Start off by checking the basics, independent of `Simultaneous-Use`.
+
+As always, start off with reading the debug output, and use that
+information to answer a few questions.
+
+== Did the user get Access-Accept?
+
+*No* - Fix that. Make sure that the user can be authenticated!
+
+*Yes* - FreeRADIUS told the NAS to allow the user online. This usually
+ works, but perhaps the NAS disagreed, and still dropped the user. It happens.
+
+The only way you know that a user is actually online is to check the
+accounting data. So we will do that next.
+
+== Did the server then get an Accounting-Request for that user?
+
+*No* - The NAS isn't sending accounting packets, Simultaneous-Use will never work.
+
+Go fix the NAS so that it sends accounting packets.
+
+*Yes* - The NAS is telling FreeRADIUS that it allowed the user online,
+ and the user has an active session. We now have to see where that data is stored.
+
+== Did the accounting data go into the radacct table?
+
+As always, Read the debug output.
+
+*No* - There is nothing in the debug output about radacct? Configure the server to write accounting data to SQL
+
+ou can use `radclient` to send fake accounting packets for testing.
+Use a real accounting packet as a template for input to `radclient`,
+but change the `User-Name` so that the tests don't affect real users.
+
+
+*Yes* - You see successful `INSERT` or `UPDATE` lines in `radacct`. That's good!
+
+== One last check
+
+Double-check the radacct database using an SQL client. Just to be sure that the data is really there.
+
+== It is now set up correctly to track user sessions
+
+If all that works, then the server is set up correctly to authenticate
+users, and to store their data in SQL. This is the foundation for
+`Simultaneous-Use`.
+
+== Set Simultaneous-Use
+
+Then, configure the server to set `Simultaneous-Use=1`. That tells the server to enforce `Simultaneous-Use`. That configuration can go into the `files` module, `sql`, or whereever else you want.
+
+You will also need to configure the `default` virtual server to check session data in SQL. Look for `Simultaneous-Use` in `sites-available/default`. Uncomment the line containing `sql`
+
+== Double check that a user can still log in!
+
+Go through all of the above steps _again_, checking that the user can
+log in, and that the server is receiving accounting packets.
+
+This time, also look for the debug output to contain:
+
+```
+# Executing section session from file ...
+session {
+```
+
+That shows it is checking the `session` database. If all goes well, the next few lines after that should show that it is checking `sql`.
+
+If the above text doesn't appear, then the server isn't getting told to set `Simultaneous-Use = 1`. You will have to fix that before going to the next step.
+
+If the user has not logged in yet, you will see an `Access-Accept`. Otherwise, if the user already has an active session, the server should say that the user is being rejected due to multiple logins.
diff --git a/doc/antora/modules/installation/pages/dependencies.adoc b/doc/antora/modules/installation/pages/dependencies.adoc
index e910e76..3fb3667 100644
--- a/doc/antora/modules/installation/pages/dependencies.adoc
+++ b/doc/antora/modules/installation/pages/dependencies.adoc
@@ -1,9 +1,8 @@
= FreeRADIUS Dependencies
Some external dependencies must be installed before building or
-running FreeRADIUS. The core depends on two mandatory libraries:
-`libtalloc` for memory management and `libkqueue` for event
-handling.
+running FreeRADIUS. For version 3, the core depends on one
+mandatory library: `libtalloc` for memory management.
Many of the modules also have optional dependencies. For example,
the LDAP module requires LDAP client libraries to be installed
@@ -29,30 +28,8 @@ https://talloc.samba.org/talloc/doc/html/index.html
`# apt-get install libtalloc-dev`
-*RedHat or CentOS*
+*RedHat, CentOS, Rocky Linux or equivalent*
```
-# subscription-manager repos --enable rhel-7-server-optional-rpms
-# yum install libtalloc-dev
-```
-
-=== kqueue
-
-Kqueue is an event / timer API originally written for BSD systems.
-It is _much_ simpler to use than third-party event libraries. A
-library, `libkqueue`, is available for Linux systems.
-
-*OSX*
-
-_kqueue is already available, there is nothing to install._
-
-*Debian, Ubuntu and `dpkg`-based systems*
-
-`# apt-get install libkqueue-dev`
-
-*RedHat or CentOS*
-
-```
-# subscription-manager repos --enable rhel-7-server-optional-rpms
-# yum install libkqueue-dev
+# yum install libtalloc-devel
```
diff --git a/doc/antora/modules/unlang/nav.adoc b/doc/antora/modules/unlang/nav.adoc
index 77be328..e2d68b3 100644
--- a/doc/antora/modules/unlang/nav.adoc
+++ b/doc/antora/modules/unlang/nav.adoc
@@ -35,7 +35,7 @@
** xref:condition/index.adoc[Conditional Expressions]
*** xref:condition/cmp.adoc[Comparisons]
*** xref:condition/operands.adoc[Operands]
-*** xref:condition/return_code.adoc[The Return Code Operator]
+*** xref:condition/return_codes.adoc[The Return Code Operator]
*** xref:condition/eq.adoc[The '==' Operator]
*** xref:condition/and.adoc[The '&&' Operator]
*** xref:condition/or.adoc[The '||' Operator]
diff --git a/doc/antora/modules/unlang/pages/case.adoc b/doc/antora/modules/unlang/pages/case.adoc
index ba2b5fe..2d5749d 100644
--- a/doc/antora/modules/unlang/pages/case.adoc
+++ b/doc/antora/modules/unlang/pages/case.adoc
@@ -14,7 +14,7 @@ outside of a xref:switch.adoc[switch] statement.
The `<match>` text can be an attribute reference such as `&User-Name`,
-or it can be a xref:type/string/index.adoc[string]. If the match
+or it can be a xref:type/index.adoc[string]. If the match
text is a dynamically expanded string, then the match is performed on
the output of the string expansion.
diff --git a/doc/antora/modules/unlang/pages/condition/index.adoc b/doc/antora/modules/unlang/pages/condition/index.adoc
index b9d9d5f..10a84c8 100644
--- a/doc/antora/modules/unlang/pages/condition/index.adoc
+++ b/doc/antora/modules/unlang/pages/condition/index.adoc
@@ -18,7 +18,7 @@ Conditions are expressed using the following syntax:
|=====
| Syntax | Description
| xref:attr.adoc[&Attribute-Name] | Check for attribute existence.
-| xref:condition/return_code.adoc[rcode] | Check return code of a previous module.
+| xref:condition/return_codes.adoc[rcode] | Check return code of a previous module.
| xref:condition/operands.adoc[data] | Check value of data.
| xref:condition/cmp.adoc[lhs OP rhs] | Compare two kinds of data.
| xref:condition/para.adoc[( condition )] | Check sub-condition
diff --git a/doc/antora/modules/unlang/pages/condition/operands.adoc b/doc/antora/modules/unlang/pages/condition/operands.adoc
index 4a2d00b..5b19af3 100644
--- a/doc/antora/modules/unlang/pages/condition/operands.adoc
+++ b/doc/antora/modules/unlang/pages/condition/operands.adoc
@@ -11,7 +11,7 @@ integer
----
Any text not matching xref:attr.adoc[&Attribute-Name] or
-xref:condition/return_code.adoc[Return Code] is interpreted as a value for a
+xref:condition/return_codes.adoc[Return Code] is interpreted as a value for a
particular xref:type/index.adoc[data type].
Double-quoted strings and back-quoted strings are dynamically expanded
diff --git a/doc/antora/modules/unlang/pages/default.adoc b/doc/antora/modules/unlang/pages/default.adoc
index 3b298f6..30912ef 100644
--- a/doc/antora/modules/unlang/pages/default.adoc
+++ b/doc/antora/modules/unlang/pages/default.adoc
@@ -14,7 +14,7 @@ outside of a xref:switch.adoc[switch] statement.
The `<match>` text can be an attribute reference such as `&User-Name`,
-or it can be a xref:type/string/index.adoc[string]. If the match
+or it can be a xref:type/index.adoc[string]. If the match
text is a dynamically expanded string, then the match is performed on
the output of the string expansion.
diff --git a/doc/antora/modules/unlang/pages/type/index.adoc b/doc/antora/modules/unlang/pages/type/index.adoc
index 7d0d70f..f26489b 100644
--- a/doc/antora/modules/unlang/pages/type/index.adoc
+++ b/doc/antora/modules/unlang/pages/type/index.adoc
@@ -6,7 +6,7 @@ conditional expressions or when assigning a value to an attribute.
== Using Data Types
The server support a wide range of data types, as given in the
-xref:unlang/type/all_types.adoc[list of data types] page. The choice
+xref:type/all_types.adoc[list of data types] page. The choice
of which data type applies is determined by the context in which that
data type is used. This context is usually taken from an attribute
which is being assigned a value.
@@ -55,7 +55,7 @@ contains special characters that may otherwise confuse the parser.
`"192.168.0.2"`:: xref:type/string/double.adoc[Double-quoted string].
+
The contents of the string are dynamically expanded as described in
-the xref:unlang/xlat/index.adoc[dynamic expansion] page. The
+the xref:xlat/index.adoc[dynamic expansion] page. The
resulting output is then interpreted as the given data type.
`{backtick}/bin/echo 192.168.0.2{backtick}`:: xref:type/string/backticks.adoc[backtick-quoted string].
@@ -110,7 +110,7 @@ interpreted as the data type `ipaddr`, and not as the literal string
`"192.0.2."`.
For a full list of data types which can be used in a cast, please see
-the xref:unlang/type/all_types.adoc[list of data types] page, and the
+the xref:type/all_types.adoc[list of data types] page, and the
"Basic Type Types" section.
// Copyright (C) 2020 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
diff --git a/doc/antora/modules/unlang/pages/xlat/builtin.adoc b/doc/antora/modules/unlang/pages/xlat/builtin.adoc
index f236a57..10d3148 100644
--- a/doc/antora/modules/unlang/pages/xlat/builtin.adoc
+++ b/doc/antora/modules/unlang/pages/xlat/builtin.adoc
@@ -782,7 +782,7 @@ Return named subcapture value from the last regular expression evaluated.
Results of named capture groups are available using the `%{regex:<named capture
group>}` expansion. They will also be accessible using the numbered expansions
-described xref:builtin.adoc#_0_32[above].
+described xref:#_0_32[above].
Every time a regular expression is evaluated, whether it matches or not,
the named capture group values will be cleared.