2 * stats.c Internal statistics handling.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2008 The FreeRADIUS server project
21 * Copyright 2008 Alan DeKok <aland@deployingradius.com>
24 #include <freeradius-devel/ident.h>
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/rad_assert.h>
32 static struct timeval start_time;
33 static struct timeval hup_time;
35 fr_stats_t radius_auth_stats = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
36 #ifdef WITH_ACCOUNTING
37 fr_stats_t radius_acct_stats = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
41 fr_stats_t proxy_auth_stats = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
42 #ifdef WITH_ACCOUNTING
43 fr_stats_t proxy_acct_stats = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
47 void request_stats_final(REQUEST *request)
49 if (request->master_state == REQUEST_COUNTED) return;
51 if ((request->listener->type != RAD_LISTEN_NONE) &&
52 (request->listener->type != RAD_LISTEN_AUTH) &&
53 (request->listener->type != RAD_LISTEN_ACCT)) return;
56 * Update the statistics.
58 * Note that we do NOT do this in a child thread.
59 * Instead, we update the stats when a request is
60 * deleted, because only the main server thread calls
61 * this function, which makes it thread-safe.
63 switch (request->reply->code) {
64 case PW_AUTHENTICATION_ACK:
65 radius_auth_stats.total_responses++;
66 radius_auth_stats.total_access_accepts++;
67 request->listener->stats.total_responses++;
68 request->listener->stats.total_access_accepts++;
69 if (request->client && request->client->auth) {
70 request->client->auth->total_access_accepts++;
74 case PW_AUTHENTICATION_REJECT:
75 radius_auth_stats.total_responses++;
76 radius_auth_stats.total_access_rejects++;
77 request->listener->stats.total_responses++;
78 request->listener->stats.total_access_rejects++;
79 if (request->client && request->client->auth) {
80 request->client->auth->total_access_rejects++;
84 case PW_ACCESS_CHALLENGE:
85 radius_auth_stats.total_responses++;
86 radius_auth_stats.total_access_challenges++;
87 request->listener->stats.total_responses++;
88 request->listener->stats.total_access_challenges++;
89 if (request->client && request->client->auth) {
90 request->client->auth->total_access_challenges++;
94 #ifdef WITH_ACCOUNTING
95 case PW_ACCOUNTING_RESPONSE:
96 radius_acct_stats.total_responses++;
97 request->listener->stats.total_responses++;
98 if (request->client && request->client->acct) {
99 request->client->acct->total_responses++;
105 * No response, it must have been a bad
109 if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
110 radius_auth_stats.total_bad_authenticators++;
111 request->listener->stats.total_bad_authenticators++;
112 if (request->client && request->client->auth) {
113 request->client->auth->total_bad_authenticators++;
123 if (!request->proxy) goto done; /* simplifies formatting */
125 switch (request->proxy_reply->code) {
126 case PW_AUTHENTICATION_REQUEST:
127 proxy_auth_stats.total_requests += request->num_proxied_requests;
128 request->proxy_listener->stats.total_requests += request->num_proxied_requests;
129 request->home_server->stats.total_requests += request->num_proxied_requests;
132 #ifdef WITH_ACCOUNTING
133 case PW_ACCOUNTING_REQUEST:
134 proxy_acct_stats.total_requests++;
135 request->proxy_listener->stats.total_requests += request->num_proxied_requests;
136 request->home_server->stats.total_requests += request->num_proxied_requests;
144 if (!request->proxy_reply) goto done; /* simplifies formatting */
146 switch (request->proxy_reply->code) {
147 case PW_AUTHENTICATION_ACK:
148 proxy_auth_stats.total_responses += request->num_proxied_responses;
149 proxy_auth_stats.total_access_accepts += request->num_proxied_responses;
150 request->proxy_listener->stats.total_responses += request->num_proxied_responses;
151 request->home_server->stats.total_access_accepts += request->num_proxied_responses;
152 request->home_server->stats.total_responses += request->num_proxied_responses;
153 request->home_server->stats.total_access_accepts += request->num_proxied_responses;
156 case PW_AUTHENTICATION_REJECT:
157 proxy_auth_stats.total_responses += request->num_proxied_responses;
158 proxy_auth_stats.total_access_rejects += request->num_proxied_responses;
159 request->proxy_listener->stats.total_responses += request->num_proxied_responses;
160 request->proxy_listener->stats.total_access_rejects += request->num_proxied_responses;
161 request->home_server->stats.total_responses += request->num_proxied_responses;
162 request->home_server->stats.total_access_rejects += request->num_proxied_responses;
165 case PW_ACCESS_CHALLENGE:
166 proxy_auth_stats.total_responses += request->num_proxied_responses;
167 proxy_auth_stats.total_access_challenges += request->num_proxied_responses;
168 request->proxy_listener->stats.total_responses += request->num_proxied_responses;
169 request->proxy_listener->stats.total_access_challenges += request->num_proxied_responses;
170 request->home_server->stats.total_responses += request->num_proxied_responses;
171 request->home_server->stats.total_access_challenges += request->num_proxied_responses;
174 #ifdef WITH_ACCOUNTING
175 case PW_ACCOUNTING_RESPONSE:
176 radius_acct_stats.total_responses++;
177 request->proxy_listener->stats.total_responses++;
178 request->home_server->stats.total_responses++;
183 proxy_auth_stats.total_unknown_types++;
184 request->proxy_listener->stats.total_unknown_types++;
185 request->home_server->stats.total_unknown_types++;
190 #endif /* WITH_PROXY */
192 request->master_state = REQUEST_COUNTED;
195 typedef struct fr_stats2vp {
203 static fr_stats2vp authvp[] = {
204 { 128, offsetof(fr_stats_t, total_requests) },
205 { 129, offsetof(fr_stats_t, total_access_accepts) },
206 { 130, offsetof(fr_stats_t, total_access_rejects) },
207 { 131, offsetof(fr_stats_t, total_access_challenges) },
208 { 132, offsetof(fr_stats_t, total_responses) },
209 { 133, offsetof(fr_stats_t, total_dup_requests) },
210 { 134, offsetof(fr_stats_t, total_malformed_requests) },
211 { 135, offsetof(fr_stats_t, total_bad_authenticators) },
212 { 136, offsetof(fr_stats_t, total_packets_dropped) },
213 { 137, offsetof(fr_stats_t, total_unknown_types) },
220 * Proxied authentication requests.
222 static fr_stats2vp proxy_authvp[] = {
223 { 138, offsetof(fr_stats_t, total_requests) },
224 { 139, offsetof(fr_stats_t, total_access_accepts) },
225 { 140, offsetof(fr_stats_t, total_access_rejects) },
226 { 141, offsetof(fr_stats_t, total_access_challenges) },
227 { 142, offsetof(fr_stats_t, total_responses) },
228 { 143, offsetof(fr_stats_t, total_dup_requests) },
229 { 144, offsetof(fr_stats_t, total_malformed_requests) },
230 { 145, offsetof(fr_stats_t, total_bad_authenticators) },
231 { 146, offsetof(fr_stats_t, total_packets_dropped) },
232 { 147, offsetof(fr_stats_t, total_unknown_types) },
238 #ifdef WITH_ACCOUNTING
242 static fr_stats2vp acctvp[] = {
243 { 148, offsetof(fr_stats_t, total_requests) },
244 { 149, offsetof(fr_stats_t, total_responses) },
245 { 150, offsetof(fr_stats_t, total_dup_requests) },
246 { 151, offsetof(fr_stats_t, total_malformed_requests) },
247 { 152, offsetof(fr_stats_t, total_bad_authenticators) },
248 { 153, offsetof(fr_stats_t, total_packets_dropped) },
249 { 154, offsetof(fr_stats_t, total_unknown_types) },
254 static fr_stats2vp proxy_acctvp[] = {
255 { 155, offsetof(fr_stats_t, total_requests) },
256 { 156, offsetof(fr_stats_t, total_responses) },
257 { 157, offsetof(fr_stats_t, total_dup_requests) },
258 { 158, offsetof(fr_stats_t, total_malformed_requests) },
259 { 159, offsetof(fr_stats_t, total_bad_authenticators) },
260 { 160, offsetof(fr_stats_t, total_packets_dropped) },
261 { 161, offsetof(fr_stats_t, total_unknown_types) },
267 static fr_stats2vp client_authvp[] = {
268 { 128, offsetof(fr_stats_t, total_requests) },
269 { 129, offsetof(fr_stats_t, total_access_accepts) },
270 { 130, offsetof(fr_stats_t, total_access_rejects) },
271 { 131, offsetof(fr_stats_t, total_access_challenges) },
272 { 132, offsetof(fr_stats_t, total_responses) },
273 { 133, offsetof(fr_stats_t, total_dup_requests) },
274 { 134, offsetof(fr_stats_t, total_malformed_requests) },
275 { 135, offsetof(fr_stats_t, total_bad_authenticators) },
276 { 136, offsetof(fr_stats_t, total_packets_dropped) },
277 { 137, offsetof(fr_stats_t, total_unknown_types) },
281 #ifdef WITH_ACCOUNTING
282 static fr_stats2vp client_acctvp[] = {
283 { 155, offsetof(fr_stats_t, total_requests) },
284 { 156, offsetof(fr_stats_t, total_responses) },
285 { 157, offsetof(fr_stats_t, total_dup_requests) },
286 { 158, offsetof(fr_stats_t, total_malformed_requests) },
287 { 159, offsetof(fr_stats_t, total_bad_authenticators) },
288 { 160, offsetof(fr_stats_t, total_packets_dropped) },
289 { 161, offsetof(fr_stats_t, total_unknown_types) },
294 #define FR2ATTR(x) ((11344 << 16) | (x))
296 static void request_stats_addvp(REQUEST *request,
297 fr_stats2vp *table, fr_stats_t *stats)
302 for (i = 0; table[i].attribute != 0; i++) {
303 vp = radius_paircreate(request, &request->reply->vps,
304 FR2ATTR(table[i].attribute),
308 vp->vp_integer = *(int *)(((char *) stats) + table[i].offset);
313 void request_stats_reply(REQUEST *request)
315 VALUE_PAIR *flag, *vp;
318 * Statistics are available ONLY on a "status" port.
320 rad_assert(request->packet->code == PW_STATUS_SERVER);
321 rad_assert(request->listener->type == RAD_LISTEN_NONE);
323 flag = pairfind(request->packet->vps, FR2ATTR(127));
324 if (!flag || (flag->vp_integer == 0)) return;
326 if (((flag->vp_integer & 0x01) != 0) &&
327 ((flag->vp_integer & 0xc0) == 0)) {
328 request_stats_addvp(request, authvp, &radius_auth_stats);
331 #ifdef WITH_ACCOUNTING
332 if (((flag->vp_integer & 0x02) != 0) &&
333 ((flag->vp_integer & 0xc0) == 0)) {
334 request_stats_addvp(request, acctvp, &radius_acct_stats);
339 if (((flag->vp_integer & 0x04) != 0) &&
340 ((flag->vp_integer & 0x20) == 0)) {
341 request_stats_addvp(request, proxy_authvp, &proxy_auth_stats);
344 #ifdef WITH_ACCOUNTING
345 if (((flag->vp_integer & 0x08) != 0) &&
346 ((flag->vp_integer & 0x20) == 0)) {
347 request_stats_addvp(request, proxy_acctvp, &proxy_acct_stats);
352 if ((flag->vp_integer & 0x10) != 0) {
353 vp = radius_paircreate(request, &request->reply->vps,
354 FR2ATTR(176), PW_TYPE_DATE);
355 if (vp) vp->vp_date = start_time.tv_sec;
356 vp = radius_paircreate(request, &request->reply->vps,
357 FR2ATTR(177), PW_TYPE_DATE);
358 if (vp) vp->vp_date = hup_time.tv_sec;
360 #ifdef HAVE_PTHREAD_H
361 int i, array[RAD_LISTEN_MAX];
363 thread_pool_queue_stats(array);
365 for (i = 0; i <= RAD_LISTEN_DETAIL; i++) {
366 vp = radius_paircreate(request, &request->reply->vps,
371 vp->vp_integer = array[i];
376 if ((flag->vp_integer & 0x20) != 0) {
378 VALUE_PAIR *server_ip, *server_port;
379 RADCLIENT *client = NULL;
380 RADCLIENT_LIST *cl = NULL;
383 * See if we need to look up the client by server
386 server_ip = pairfind(request->packet->vps, FR2ATTR(170));
388 server_port = pairfind(request->packet->vps,
393 ipaddr.ipaddr.ip4addr.s_addr = server_ip->vp_ipaddr;
394 cl = listener_find_client_list(&ipaddr, server_port->vp_integer);
397 * Not found: don't do anything
404 vp = pairfind(request->packet->vps, FR2ATTR(167));
407 ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
408 client = client_find(cl, &ipaddr);
411 * Else look it up by number.
413 } else if ((vp = pairfind(request->packet->vps,
414 FR2ATTR(168))) != NULL) {
415 client = client_findbynumber(cl, vp->vp_integer);
420 * If found, echo it back, along with
421 * the requested statistics.
423 pairadd(&request->reply->vps, paircopyvp(vp));
426 * When retrieving client by number, also
427 * echo back it's IP address.
429 if ((vp->type == PW_TYPE_INTEGER) &&
430 (client->ipaddr.af == AF_INET)) {
431 vp = radius_paircreate(request,
432 &request->reply->vps,
436 vp->vp_ipaddr = client->ipaddr.ipaddr.ip4addr.s_addr;
439 if (client->prefix != 32) {
440 vp = radius_paircreate(request,
441 &request->reply->vps,
445 vp->vp_integer = client->prefix;
451 pairadd(&request->reply->vps,
452 paircopyvp(server_ip));
453 pairadd(&request->reply->vps,
454 paircopyvp(server_port));
458 ((flag->vp_integer & 0x01) != 0)) {
459 request_stats_addvp(request, client_authvp,
462 #ifdef WITH_ACCOUNTING
464 ((flag->vp_integer & 0x01) != 0)) {
465 request_stats_addvp(request, client_acctvp,
469 } /* else client wasn't found, don't echo it back */
472 if (((flag->vp_integer & 0x40) != 0) &&
473 ((flag->vp_integer & 0x03) != 0)) {
475 VALUE_PAIR *server_ip, *server_port;
479 * See if we need to look up the server by socket
482 server_ip = pairfind(request->packet->vps, FR2ATTR(170));
483 if (!server_ip) return;
485 server_port = pairfind(request->packet->vps,
487 if (!server_port) return;
490 ipaddr.ipaddr.ip4addr.s_addr = server_ip->vp_ipaddr;
491 this = listener_find_byipaddr(&ipaddr,
492 server_port->vp_integer);
495 * Not found: don't do anything
499 pairadd(&request->reply->vps,
500 paircopyvp(server_ip));
501 pairadd(&request->reply->vps,
502 paircopyvp(server_port));
504 if (((flag->vp_integer & 0x01) != 0) &&
505 ((request->listener->type == RAD_LISTEN_AUTH) ||
506 (request->listener->type == RAD_LISTEN_NONE))) {
507 request_stats_addvp(request, authvp, &this->stats);
510 #ifdef WITH_ACCOUNTING
511 if (((flag->vp_integer & 0x02) != 0) &&
512 ((request->listener->type == RAD_LISTEN_ACCT) ||
513 (request->listener->type == RAD_LISTEN_NONE))) {
514 request_stats_addvp(request, acctvp, &this->stats);
522 if (((flag->vp_integer & 0x80) != 0) &&
523 ((flag->vp_integer & 0x03) != 0)) {
525 VALUE_PAIR *server_ip, *server_port;
529 * See if we need to look up the server by socket
532 server_ip = pairfind(request->packet->vps, FR2ATTR(170));
533 if (!server_ip) return;
535 server_port = pairfind(request->packet->vps,
537 if (!server_port) return;
540 ipaddr.ipaddr.ip4addr.s_addr = server_ip->vp_ipaddr;
541 home = home_server_find(&ipaddr, server_port->vp_integer);
544 * Not found: don't do anything
548 pairadd(&request->reply->vps,
549 paircopyvp(server_ip));
550 pairadd(&request->reply->vps,
551 paircopyvp(server_port));
553 vp = radius_paircreate(request, &request->reply->vps,
554 FR2ATTR(172), PW_TYPE_INTEGER);
555 if (vp) vp->vp_integer = home->currently_outstanding;
557 vp = radius_paircreate(request, &request->reply->vps,
558 FR2ATTR(173), PW_TYPE_INTEGER);
559 if (vp) vp->vp_integer = home->state;
561 if ((home->state == HOME_STATE_ALIVE) &&
562 (home->revive_time.tv_sec != 0)) {
563 vp = radius_paircreate(request, &request->reply->vps,
564 FR2ATTR(175), PW_TYPE_DATE);
565 if (vp) vp->vp_date = home->revive_time.tv_sec;
568 if (home->state == HOME_STATE_IS_DEAD) {
569 vp = radius_paircreate(request, &request->reply->vps,
570 FR2ATTR(174), PW_TYPE_DATE);
571 if (vp) vp->vp_date = home->zombie_period_start.tv_sec + home->zombie_period;
574 if (((flag->vp_integer & 0x01) != 0) &&
575 ((request->listener->type == RAD_LISTEN_AUTH) ||
576 (request->listener->type == RAD_LISTEN_NONE))) {
577 request_stats_addvp(request, proxy_authvp,
581 #ifdef WITH_ACCOUNTING
582 if (((flag->vp_integer & 0x02) != 0) &&
583 ((request->listener->type == RAD_LISTEN_ACCT) ||
584 (request->listener->type == RAD_LISTEN_NONE))) {
585 request_stats_addvp(request, proxy_acctvp,
592 void radius_stats_init(int flag)
595 gettimeofday(&start_time, NULL);
596 hup_time = start_time; /* it's just nicer this way */
598 gettimeofday(&hup_time, NULL);
602 #endif /* WITH_STATS */