Skip to content

Commit 23593f8

Browse files
noladealandekok
authored andcommitted
Rearrange debugging documentation
1 parent 1f0df07 commit 23593f8

File tree

7 files changed

+355
-331
lines changed

7 files changed

+355
-331
lines changed

doc/antora/modules/ROOT/nav.adoc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
* xref:index.adoc[Introduction]
22
** xref:getstarted.adoc[Getting Started]
3-
*** xref:radiusd_x.adoc[Debugging]
3+
*** xref:debugging/radiusd_X.adoc[Debugging]
4+
*** xref:debugging/startup.adoc[Startup]
5+
*** xref:debugging/processing.adoc[Processing Packets]
46
*** xref:gethelp.adoc[Getting Help]
57
** xref:bestpractices.adoc[Best Practices]
68
** xref:faq.adoc[Frequently Asked Question (FAQ)]
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
# Packet Processing
2+
3+
Each line (or most of them) of the packet processing output starts with a request number, e.g. `(0)`. This number lets you track debug messages which are all for one packet. Messages from different packets may be inter-mingled, due to threading or proxying. Prefixing the messages with a number allows the messages to be easily differentiated.
4+
5+
## Receiving a packet
6+
7+
The first message for a packet tells you what type of packet was received, what it's RADIUS ID is, and the source / destination IP / port information.
8+
9+
(0) Received Access-Request Id 104 from 127.0.0.1:33278 to 127.0.0.1:1812 length 73
10+
11+
After that, it prints out all of the attributes which were received in the packet.
12+
[%collapsible]
13+
====
14+
(0) User-Name = "bob"
15+
(0) User-Password = "wrongpassword"
16+
(0) NAS-IP-Address = 127.0.1.1
17+
(0) NAS-Port = 0
18+
(0) Message-Authenticator = 0x3d27116b37323e4f629b4e8217fc25c8
19+
====
20+
21+
[NOTE]
22+
====
23+
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.
24+
====
25+
26+
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`.
27+
28+
(0) # Executing section authorize from file /etc/raddb/sites-enabled/default
29+
(0) authorize {
30+
31+
The `authorize` section contains a number of modules, along with unlang keywords like `if`, `update`, etc.
32+
33+
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`.
34+
[%collapsible]
35+
====
36+
(0) suffix: Checking for suffix after "@"
37+
(0) suffix: No '@' in User-Name = "bob", looking up realm NULL
38+
(0) suffix: No such realm "NULL"
39+
====
40+
41+
The server core then prints out the "return code" of the module. See `man unlang` for a deeper explanation of return codes.
42+
43+
(0) [suffix] = noop
44+
(0) [files] = noop
45+
46+
The `authorize` section also has a return code.
47+
48+
(0) } # authorize = noop
49+
50+
In this case, the user is unknown, so they will be rejected.
51+
52+
(0) ERROR: No Auth-Type found: rejecting the user via Post-Auth-Type = Reject
53+
(0) Failed to authenticate the user
54+
55+
The packet is processed through the `Post-Auth-Type REJECT` section
56+
[%collapsible]
57+
====
58+
(0) Using Post-Auth-Type Reject
59+
(0) # Executing group from file /etc/raddb/sites-enabled/default
60+
(0) Post-Auth-Type REJECT {
61+
====
62+
63+
That section contains more modules and unlang statements.
64+
65+
Here, the `attr_filter` module is removing attributes which are forbidden from appearing in an Access-Reject packet.
66+
[%collapsible]
67+
====
68+
(0) attr_filter.access_reject: EXPAND %{User-Name}
69+
(0) attr_filter.access_reject: --> bob
70+
(0) attr_filter.access_reject: Matched entry DEFAULT at line 11
71+
(0) [attr_filter.access_reject] = updated
72+
(0) [eap] = noop
73+
(0) policy remove_reply_message_if_eap {
74+
(0) if (&reply:EAP-Message && &reply:Reply-Message) {
75+
(0) if (&reply:EAP-Message && &reply:Reply-Message) -> FALSE
76+
(0) else {
77+
(0) [noop] = noop
78+
(0) } # else = noop
79+
(0) } # policy remove_reply_message_if_eap = noop
80+
====
81+
82+
Finally, the `Post-Auth-Type REJECT` section is done.
83+
84+
(0) } # Post-Auth-Type REJECT = updated
85+
86+
Since this is an Access-Reject, it is delayed for one second to prevent password attacks. The `reject_delay` configuration above control this delay.
87+
88+
(0) Delaying response for 1.000000 seconds
89+
90+
The server then sleeps for a while, waking up periodically to deal with internal book-keeping.
91+
92+
Waking up in 0.3 seconds.
93+
Waking up in 0.6 seconds.
94+
95+
Finally after a one-second delay, the server wakes up and sends the Access-Reject packet.
96+
97+
(0) Sending delayed response
98+
99+
The IP / port printed here is the mirror of the one printed for the Access-Request, above. This indicates that it's a reply to an earlier request.
100+
101+
(0) Sent Access-Reject Id 104 from 127.0.0.1:1812 to 127.0.0.1:33278 length 20
102+
103+
If there are any attributes in the reply packet, they will be printed here. In this case, there are none.
104+
105+
[NOTE]
106+
====
107+
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.
108+
====
109+
110+
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.
111+
112+
The server then sleeps for a while:
113+
114+
Waking up in 3.9 seconds.
115+
116+
And then cleans up the request and it's associated response. This delay is controlled by `cleanup_delay`, which was seen earlier in the debug output.
117+
118+
(0) Cleaning up request packet ID 104 with timestamp +23
119+
120+
Since there's nothing more to do, we're back to this message.
121+
122+
Ready to process requests
123+
124+
The debug log has another packet, which we will skip, as it's largely the same as the previous one.
125+
[%collapsible]
126+
====
127+
(1) Received Access-Request Id 146 from 127.0.0.1:40967 to 127.0.0.1:1812 length 73
128+
(1) User-Name = "bob"
129+
(1) User-Password = "wrongagain"
130+
(1) NAS-IP-Address = 127.0.1.1
131+
(1) NAS-Port = 0
132+
====
133+
134+
The debug log then shows a successful authentication.
135+
136+
The input packet is largely the same, but has a different `User-Name` and `User-Password` attribute.
137+
[%collapsible]
138+
====
139+
(2) Received Access-Request Id 135 from 127.0.0.1:40344 to 127.0.0.1:1812 length 77
140+
(2) User-Name = "bob@int"
141+
(2) User-Password = "test"
142+
(2) NAS-IP-Address = 127.0.1.1
143+
(2) NAS-Port = 0
144+
====
145+
146+
The `Message-Authenticator` attribute is a cryptographic signature of the packet, and has no other meaning.
147+
148+
(2) Message-Authenticator = 0x3b3f4cf11005dcccfe78bb4a5830dd52
149+
150+
We start the `authorize` section again/
151+
152+
(2) # Executing section authorize from file /etc/raddb/sites-enabled/default
153+
(2) authorize {
154+
155+
This time the `suffix` module does find a suffix.
156+
157+
(2) suffix: Checking for suffix after "@"
158+
(2) suffix: Looking up realm "int" for User-Name = "bob@int"
159+
160+
The realm `int` is defined above in the `realm` configuration.
161+
162+
(2) suffix: Found realm "int"
163+
164+
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.
165+
[%collapsible]
166+
====
167+
(2) suffix: Adding Stripped-User-Name = "bob"
168+
(2) suffix: Adding Realm = "int"
169+
(2) suffix: Proxying request from user bob to realm int
170+
(2) suffix: Preparing to proxy authentication request to realm "int"
171+
(2) [suffix] = updated
172+
(2) [files] = noop
173+
(2) } # authorize = updated
174+
(2) Starting proxy to home server (null) port 1812
175+
====
176+
177+
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.
178+
179+
Proxying to virtual server inner-tunnel
180+
(2) # Executing section authorize from file /etc/raddb/sites-enabled/inner-tunnel
181+
(2) authorize {
182+
183+
The `files` module matches the user name and realm, at `line 1` of the `users` file. This output lets you know exactly which entry was matched.
184+
185+
If the server does not do what you expect it to do, you should read `line 1` of the `users` file (or whatever entry matched), to verify that the entry is what you expect it to be.
186+
187+
(2) files: users: Matched entry bob@int at line 1
188+
(2) [files] = ok
189+
190+
The `pap` module sees the `Cleartext-Password` which was set in the `users` file, along with the `User-Password` that came from the packet. The module then sets `Auth-Type := PAP`. This is so that the `authenticate` section will run the `pap` module, which will then authenticate the user.
191+
192+
(2) [pap] = updated
193+
(2) } # authorize = updated
194+
195+
It now runs `Auth-Type PAP`
196+
[%collapsible]
197+
====
198+
(2) Found Auth-Type = PAP
199+
(2) # Executing group from file /etc/raddb/sites-enabled/inner-tunnel
200+
(2) Auth-Type PAP {
201+
====
202+
203+
The `pap` module tells you that everything is OK.
204+
[%collapsible]
205+
====
206+
(2) pap: Login attempt with password
207+
(2) pap: Comparing with "known good" Cleartext-Password
208+
(2) pap: User authenticated successfully
209+
(2) [pap] = ok
210+
(2) } # Auth-Type PAP = ok
211+
====
212+
213+
It now runs the normal `post-auth` section
214+
[%collapsible]
215+
====
216+
(2) # Executing section post-auth from file /etc/raddb/sites-enabled/inner-tunnel
217+
(2) post-auth {
218+
(2) update reply {
219+
(2) Reply-Message := "hello"
220+
(2) } # update reply = noop
221+
(2) if (0) {
222+
(2) if (0) -> FALSE
223+
(2) } # post-auth = noop
224+
(2) Finished internally proxied request.
225+
(2) Clearing existing &reply: attributes
226+
====
227+
228+
Because this is a proxied request, it now runs the `post-proxy` section of the `default` virtual server.
229+
[%collapsible]
230+
====
231+
(2) # Executing section post-proxy from file /etc/raddb/sites-enabled/default
232+
(2) post-proxy {
233+
(2) policy debug_reply {
234+
(2) if ("%{debug_attr:reply:}" == '') {
235+
(2) Attributes matching "reply:"
236+
(2) EXPAND %{debug_attr:reply:}
237+
(2) -->
238+
(2) if ("%{debug_attr:reply:}" == '') -> TRUE
239+
(2) if ("%{debug_attr:reply:}" == '') {
240+
(2) [noop] = noop
241+
(2) } # if ("%{debug_attr:reply:}" == '') = noop
242+
(2) } # policy debug_reply = noop
243+
(2) } # post-proxy = noop
244+
====
245+
246+
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.
247+
248+
(2) Found Auth-Type = Accept
249+
(2) Auth-Type = Accept, accepting the user
250+
251+
It then runs the `post-auth` section from the `default` virtual server.
252+
[%collapsible]
253+
====
254+
(2) # Executing section post-auth from file /etc/raddb/sites-enabled/default
255+
(2) post-auth {
256+
(2) update {
257+
(2) No attributes updated
258+
(2) } # update = noop
259+
(2) [exec] = noop
260+
(2) policy remove_reply_message_if_eap {
261+
(2) if (&reply:EAP-Message && &reply:Reply-Message) {
262+
(2) if (&reply:EAP-Message && &reply:Reply-Message) -> FALSE
263+
(2) else {
264+
(2) [noop] = noop
265+
(2) } # else = noop
266+
(2) } # policy remove_reply_message_if_eap = noop
267+
(2) } # post-auth = noop
268+
====
269+
270+
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.
271+
[%collapsible]
272+
====
273+
(2) Sent Access-Accept Id 135 from 127.0.0.1:1812 to 127.0.0.1:40344 length 0
274+
(2) Reply-Message := "hello"
275+
(2) Finished request
276+
Waking up in 4.9 seconds.
277+
(2) Cleaning up request packet ID 135 with timestamp +74
278+
Ready to process requests
279+
^C
280+
====
281+
282+
That is a *lot* of information to go through. We hope that this page has been useful.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Debugging
2+
3+
This debugging section outlines the steps to take if you run into issues starting or configuring the FreeRADIUS server.
4+
If your server starts up successfully, save a copy of the configuration so you always have a "known working" configuration.
5+
When the server doesn't start up, go back and verify the configuration and read the entire debug output. If you have issues, the initial steps to troubleshoot or debug the server are:
6+
7+
* Make small, discrete changes to the configuration files.
8+
* Start the server in debugging mode by entering the command *radiusd -X*
9+
* Verify that the results are what you expect
10+
* The debug output shows any configuration changes you have made:
11+
** Datastores are connected and operating.
12+
** Test packets are accepted by the server.
13+
** The debug output shows that the packets are being processed as you expect.
14+
** The response packets contain the attributes you expect to see.
15+
16+
If you can't make any progress, replace your configuration with a saved copy of a "known working" configuration, and start the server again. This process can clean up errors caused by temporary or forgotten edits.
17+
If you are still having issues, ask for help on the mailto:freeradius-users@lists.freeradius.org[freeradius-users] list. Include a description of what you are trying to do, and the entire debugging output that includes the server receiving and processing test packets.
18+
19+
## How to use `radiusd -X` (debug mode)
20+
21+
This next section explains how to read the output of `radiusd -X`.
22+
23+
The first part of the debug output is the *startup* text. Once the server is started, it prints `Ready to receive requests`. The next part of the debug output is the *packet processing* text. Both parts need to be read (and posted to the list!) in order to solve issues.
24+
25+
## If it doesn't start
26+
27+
If the server does not start at all, verify that you are running the server with sudo. If the server reboots correctly after this switch, then the problem was that the server was running as an unprivileged user.
28+
29+
If the server does not start up correctly, *the debug output will tell you why*. It will produce long descriptive error messages, telling you exactly what's wrong. In some cases, it will tell you how to fix it.
30+
31+
Look for messages like *Error* or *Warning*. If you are running the server in a terminal console, those messages will appear in red or yellow. It should be simple to scroll through the output, ignoring most of it, and looking for red *Error* text. Fixing those errors will usually allow the server to start correctly.
32+
33+
The next sections are huge and have been broken apart into two sections so it's easier for you to read though and understand the steps the RADIUS server goes through.
34+
35+
Essentially, the first section is xref:debugging/startup.adoc[*Startup Text*] where the RADIUS server reads, loads, and initilizes itself through the following processes:
36+
37+
. Reads the configuration files.
38+
. Reads the dictionaries.
39+
. Loads the config files.
40+
. Loads the policies.
41+
. Loads the server config.
42+
. Loads the proxy config.
43+
. Loads the client config.
44+
. Initializes the auth-types.
45+
. Reads and load the modules.
46+
. Loads the users file (called by Modules file).
47+
. Listen section is read and sockets initialized.
48+
49+
The next section xref:debugging/processing.adoc[*Packet Processing*] is where the server accepts, inspects, and manages the received RADIUS packets in this order:
50+
51+
. Server receives a RADIUS packet.
52+
. Authorize module is called.
53+
. Inspection of packet contents and multiple modules may be called to complete processing. A decision is made to call one of the following actions:
54+
. POST-AUTH-REJECT
55+
. POST-AUTH-ACCEPT
56+
. Server completes the post-authorization processes for the current packet.
57+
58+
59+
// Copyright (C) 2025 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
60+
// This documentation was developed by Network RADIUS SAS.

0 commit comments

Comments
 (0)