|
| 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. |
0 commit comments