Make stats secret...
[freeradius.git] / src / main / stats.c
1 /*
2  * stats.c      Internal statistics handling.
3  *
4  * Version:     $Id$
5  *
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.
10  *
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.
15  *
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
19  *
20  * Copyright 2008  The FreeRADIUS server project
21  * Copyright 2008  Alan DeKok <aland@deployingradius.com>
22  */
23
24 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/rad_assert.h>
29
30 #ifdef WITH_STATS
31
32 fr_stats_t radius_auth_stats = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
33 #ifdef WITH_ACCOUNTING
34 fr_stats_t radius_acct_stats = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
35 #endif
36
37 #ifdef WITH_PROXY
38 fr_stats_t proxy_auth_stats = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
39 #ifdef WITH_ACCOUNTING
40 fr_stats_t proxy_acct_stats = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
41 #endif
42 #endif
43
44 void request_stats_final(REQUEST *request)
45 {
46         if (request->master_state == REQUEST_COUNTED) return;
47
48         if ((request->listener->type != RAD_LISTEN_AUTH) &&
49             (request->listener->type != RAD_LISTEN_ACCT)) return;
50
51         /*
52          *      Update the statistics.
53          *
54          *      Note that we do NOT do this in a child thread.
55          *      Instead, we update the stats when a request is
56          *      deleted, because only the main server thread calls
57          *      this function, which makes it thread-safe.
58          */
59         switch (request->reply->code) {
60         case PW_AUTHENTICATION_ACK:
61                 radius_auth_stats.total_responses++;
62                 radius_auth_stats.total_access_accepts++;
63                 if (request->client && request->client->auth) {
64                         request->client->auth->accepts++;
65                 }
66                 break;
67
68         case PW_AUTHENTICATION_REJECT:
69                 radius_auth_stats.total_responses++;
70                 radius_auth_stats.total_access_rejects++;
71                 if (request->client && request->client->auth) {
72                         request->client->auth->rejects++;
73                 }
74                 break;
75
76         case PW_ACCESS_CHALLENGE:
77                 radius_auth_stats.total_responses++;
78                 radius_auth_stats.total_access_challenges++;
79                 if (request->client && request->client->auth) {
80                         request->client->auth->challenges++;
81                 }
82                 break;
83
84 #ifdef WITH_ACCOUNTING
85         case PW_ACCOUNTING_RESPONSE:
86                 radius_acct_stats.total_responses++;
87                 if (request->client && request->client->acct) {
88                         request->client->acct->responses++;
89                 }
90                 break;
91 #endif
92
93                 /*
94                  *      No response, it must have been a bad
95                  *      authenticator.
96                  */
97         case 0:
98                 if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
99                         radius_auth_stats.total_bad_authenticators++;
100                         if (request->client && request->client->auth) {
101                                 request->client->auth->bad_authenticators++;
102                         }
103                 }
104                 break;
105
106         default:
107                 break;
108         }
109
110 #ifdef WITH_PROXY
111         if (!request->proxy) goto done; /* simplifies formatting */
112                 
113         switch (request->proxy_reply->code) {
114         case PW_AUTHENTICATION_REQUEST:
115                 proxy_auth_stats.total_requests += request->num_proxied_requests;
116                 break;
117
118 #ifdef WITH_ACCOUNTING
119         case PW_ACCOUNTING_REQUEST:
120                 proxy_acct_stats.total_requests++;
121                 break;
122 #endif
123
124         default:
125                 break;
126         }
127
128         if (!request->proxy_reply) goto done;   /* simplifies formatting */
129
130         switch (request->proxy_reply->code) {
131         case PW_AUTHENTICATION_ACK:
132                 proxy_auth_stats.total_responses += request->num_proxied_responses;
133                 proxy_auth_stats.total_access_accepts += request->num_proxied_responses;
134                 break;
135
136         case PW_AUTHENTICATION_REJECT:
137                 proxy_auth_stats.total_responses += request->num_proxied_responses;
138                 proxy_auth_stats.total_access_rejects += request->num_proxied_responses;
139                 break;
140
141         case PW_ACCESS_CHALLENGE:
142                 proxy_auth_stats.total_responses += request->num_proxied_responses;
143                 proxy_auth_stats.total_access_challenges += request->num_proxied_responses;
144                 break;
145
146 #ifdef WITH_ACCOUNTING
147         case PW_ACCOUNTING_RESPONSE:
148                 radius_acct_stats.total_responses++;
149                 break;
150 #endif
151
152         default:
153                 proxy_auth_stats.total_unknown_types++;
154                 break;
155         }
156
157  done:
158 #endif /* WITH_PROXY */
159
160         request->master_state = REQUEST_COUNTED;
161 }
162
163 typedef struct fr_stats2vp {
164         int     attribute;
165         size_t  offset;
166 } fr_stats2vp;
167
168 /*
169  *      Authentication
170  */
171 static fr_stats2vp authvp[] = {
172         { 128, offsetof(fr_stats_t, total_requests) },
173         { 129, offsetof(fr_stats_t, total_access_accepts) },
174         { 130, offsetof(fr_stats_t, total_access_rejects) },
175         { 131, offsetof(fr_stats_t, total_access_challenges) },
176         { 132, offsetof(fr_stats_t, total_responses) },
177         { 133, offsetof(fr_stats_t, total_dup_requests) },
178         { 134, offsetof(fr_stats_t, total_malformed_requests) },
179         { 135, offsetof(fr_stats_t, total_bad_authenticators) },
180         { 136, offsetof(fr_stats_t, total_packets_dropped) },
181         { 137, offsetof(fr_stats_t, total_unknown_types) },
182         { 0, 0 }
183 };
184
185 #ifdef WITH_PROXY
186 /*
187  *      Proxied authentication requests.
188  */
189 static fr_stats2vp proxy_authvp[] = {
190         { 138, offsetof(fr_stats_t, total_requests) },
191         { 139, offsetof(fr_stats_t, total_access_accepts) },
192         { 140, offsetof(fr_stats_t, total_access_rejects) },
193         { 141, offsetof(fr_stats_t, total_access_challenges) },
194         { 142, offsetof(fr_stats_t, total_responses) },
195         { 143, offsetof(fr_stats_t, total_dup_requests) },
196         { 144, offsetof(fr_stats_t, total_malformed_requests) },
197         { 145, offsetof(fr_stats_t, total_bad_authenticators) },
198         { 146, offsetof(fr_stats_t, total_packets_dropped) },
199         { 147, offsetof(fr_stats_t, total_unknown_types) },
200         { 0, 0 }
201 };
202 #endif
203
204 #define FR2ATTR(x) ((11344 << 16) | (x))
205
206 void request_stats_reply(REQUEST *request)
207 {
208         int i;
209         VALUE_PAIR *vp;
210
211         if (request->packet->code != PW_STATUS_SERVER) return;
212
213         if ((request->packet->src_ipaddr.af != AF_INET) ||
214             (request->packet->src_ipaddr.ipaddr.ip4addr.s_addr != htonl(INADDR_LOOPBACK))) return;
215
216         vp = pairfind(request->packet->vps, PW_CONFIGURATION_TOKEN);
217         if (!vp || (strcmp(vp->vp_strvalue, "Statistics") != 0)) return;
218
219         for (i = 0; authvp[i].attribute != 0; i++) {
220                 vp = radius_paircreate(request, &request->reply->vps,
221                                        FR2ATTR(authvp[i].attribute),
222                                        PW_TYPE_INTEGER);
223                 if (!vp) continue;
224
225                 vp->vp_integer = *(int *)(((char *) &radius_auth_stats) + 
226                                           authvp[i].offset);
227         }
228
229 #ifdef WITH_PROXY
230         for (i = 0; proxy_authvp[i].attribute != 0; i++) {
231                 vp = radius_paircreate(request, &request->reply->vps,
232                                        FR2ATTR(proxy_authvp[i].attribute),
233                                        PW_TYPE_INTEGER);
234                 if (!vp) continue;
235
236                 vp->vp_integer = *(int *)(((char *) &proxy_auth_stats) + 
237                                           proxy_authvp[i].offset);
238         }
239 #endif
240 }
241
242 #endif /* WITH_STATS */