The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
track.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: b4d71316d4d7c0fb95f076d150c985048c850f39 $
19 * @file rlm_radius/track.c
20 * @brief Tracking RADUS client packets
21 *
22 * @copyright 2017 Network RADIUS SAS
23 */
24RCSID("$Id: b4d71316d4d7c0fb95f076d150c985048c850f39 $")
25
26#include <freeradius-devel/server/base.h>
27#include <freeradius-devel/util/rb.h>
28#include <freeradius-devel/io/application.h>
29#include <freeradius-devel/util/dlist.h>
30#include <freeradius-devel/util/debug.h>
31
32#include "track.h"
33
34/** Create an radius_track_t
35 *
36 * @param ctx the talloc ctx
37 * @return
38 * - NULL on error
39 * - radius_track_t on success
40 */
42{
43 int i;
45
46 MEM(tt = talloc_zero(ctx, radius_track_t));
47
49
50 for (i = 0; i < 256; i++) {
51 tt->id[i].id = i;
52#ifndef NDEBUG
53 tt->id[i].file = __FILE__;
54 tt->id[i].line = __LINE__;
55#endif
56 fr_dlist_insert_tail(&tt->free_list, &tt->id[i]);
57 }
58
59 return tt;
60}
61
62
63/** Ensures the entry is released when the ctx passed to radius_track_entry_reserve is freed
64 *
65 * @param[in] te_p Entry to release.
66 * @return 0
67 */
69{
71
72 return 0;
73}
74
75/** Allocate a tracking entry.
76 *
77 * @param[in] file The allocation was made in.
78 * @param[in] line The allocation was made on.
79 * @param[out] te_out Where the tracking entry should be written.
80 * If ctx is not-null, then this pointer must
81 * remain valid for the lifetime of the ctx.
82 * @param[in] ctx If not-null, the tracking entry release will
83 * be bound to the lifetime of the talloc chunk.
84 * @param[in] tt The radius_track_t tracking table.
85 * @param[in] request The request which will send the proxied packet.
86 * @param[in] code Of the outbound request.
87 * @param[in] uctx The context to associate with the request
88 * @return
89 * - 0 on success.
90 * - -1 on failure.
91 */
92#ifndef NDEBUG
94#else
96#endif
97 radius_track_entry_t **te_out,
98 TALLOC_CTX *ctx, radius_track_t *tt, request_t *request, uint8_t code, void *uctx)
99{
101
102 if (!fr_cond_assert_msg(!*te_out, "Expected tracking entry to be NULL")) return -1;
103
104retry:
105 te = fr_dlist_head(&tt->free_list);
106 if (te) {
107 fr_assert(te->request == NULL);
108
109 /*
110 * Mark it as used, and remove it from the free list.
111 */
112 fr_dlist_remove(&tt->free_list, te);
113
114 /*
115 * We've transitioned from "use it", to "oops,
116 * don't use it". Ensure that we only return IDs
117 * which are in the static array.
118 */
119 if (te != &tt->id[te->id]) {
120 talloc_free(te);
121 goto retry;
122 }
123
124 goto done;
125 }
126
127 /*
128 * There are no free entries, and we can't use the
129 * Request Authenticator. Oh well...
130 */
131 fr_strerror_const("No free entries");
132 return -1;
133
134done:
135 te->tt = tt;
136 te->request = request;
137 te->uctx = uctx;
138 te->code = code;
139#ifndef NDEBUG
140 te->operation = te->tt->operation++;
141 te->file = file;
142 te->line = line;
143#endif
144 if (ctx) {
145 te->binding = talloc_zero(ctx, radius_track_entry_t **);
146 talloc_set_destructor(te->binding, _radius_track_entry_release_on_free);
147 *(te->binding) = te_out;
148 }
149
150 /*
151 * te->id is already allocated
152 */
153 tt->num_requests++;
154
155 *te_out = te;
156
157 return 0;
158}
159
160/** Release a tracking entry
161 *
162 * @param[in] file Allocation was released in.
163 * @param[in] line Allocation was released on.
164 * @param[in,out] te_to_free The #radius_track_entry_t allocated via #radius_track_entry_reserve.
165 * @return
166 * - <0 on error
167 * - 0 on success
168 */
169#ifndef NDEBUG
171#else
173#endif
174 radius_track_entry_t **te_to_free)
175{
176 radius_track_entry_t *te = *te_to_free;
177 radius_track_t *tt;
178
179 if (!te) return 0;
180
181 tt = talloc_get_type_abort(te->tt, radius_track_t); /* Make sure table is still valid */
182
183 if (te->binding) {
184 talloc_set_destructor(te->binding, NULL); /* Disarm the destructor */
185 talloc_free(te->binding);
186 }
187
188#ifndef NDEBUG
189 te->operation = te->tt->operation++;
190 te->file = file;
191 te->line = line;
192#endif
193
194 te->request = NULL;
195
196 fr_assert(tt->num_requests > 0);
197 tt->num_requests--;
198
199 /*
200 * We're freeing a static ID, just go do that...
201 */
202 fr_assert(te == &tt->id[te->id]);
203
205
206 *te_to_free = NULL;
207
208 return 0;
209}
210
211/** Update a tracking entry with the authentication vector
212 *
213 * @param te The radius_track_entry_t, via radius_track_entry_reserve()
214 * @param vector The authentication vector for the packet we're sending
215 * @return
216 * - <0 on error
217 * - 0 on success
218 */
220{
221#ifndef NDEBUG
222 radius_track_t *tt = te->tt;
223#endif
224
225 fr_assert(tt);
226
227 memcpy(te->vector, vector, sizeof(te->vector));
228
229 /*
230 * If we're not using the Request Authenticator, the
231 * tracking entry must be in the static array.
232 *
233 * @todo - gracefully handle fallback if the server screws up.
234 */
235 fr_assert(te == &tt->id[te->id]);
236 return 0;
237}
238
239/** Find a tracking entry from a request authenticator
240 *
241 * @param tt The radius_track_t tracking table
242 * @param packet_id The ID from the RADIUS header
243 * @param vector The Request Authenticator (may be NULL)
244 * @return
245 * - NULL on "not found"
246 * - radius_track_entry_t on success
247 */
249{
251
252 (void) talloc_get_type_abort(tt, radius_track_t);
253
254 /*
255 * Just use the static array.
256 */
257 te = &tt->id[packet_id];
258
259 /*
260 * Not in use, die.
261 */
262 if (!te->request) return NULL;
263
264 if (!vector) return te;
265
266 /*
267 * Protocol-Error and Original-Packet-Vector <sigh>
268 *
269 * This should arguably have been Original-Packet-Code, but we are stupid.
270 *
271 * @todo - Allow for multiple ID arrays, one for each packet code. Or, just switch to using
272 * src/protocols/radius/id.[ch].
273 */
274 if (memcmp(te->vector, vector, sizeof(te->vector)) != 0) return NULL;
275
276 /*
277 * Ignore the Request Authenticator, as the
278 * caller doesn't have it.
279 */
280 return te;
281}
282
283
284#ifndef NDEBUG
285/** Print out the state of every tracking entry
286 *
287 * @param[in] log destination.
288 * @param[in] log_type Type of log message.
289 * @param[in] file this function was called in.
290 * @param[in] line this function was called on.
291 * @param[in] tt Table to print.
292 * @param[in] extra Callback function for printing extra detail.
293 */
294void radius_track_state_log(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line,
296{
297 size_t i;
298
299 for (i = 0; i < NUM_ELEMENTS(tt->id); i++) {
301
302 entry = &tt->id[i];
303
304 if (entry->request) {
305 fr_log(log, log_type, file, line,
306 "[%zu] %"PRIu64 " - Allocated at %s:%u to request %p (%s), uctx %p",
307 i, entry->operation,
308 entry->file, entry->line, entry->request, entry->request->name, entry->uctx);
309 } else {
310 fr_log(log, log_type, file, line,
311 "[%zu] %"PRIu64 " - Freed at %s:%u",
312 i, entry->operation, entry->file, entry->line);
313 }
314
315 if (extra) extra(log, log_type, file, line, entry);
316 }
317}
318#endif
int const char * file
Definition acutest.h:702
int const char int line
Definition acutest.h:702
#define RCSID(id)
Definition build.h:483
#define NUM_ELEMENTS(_t)
Definition build.h:337
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:156
#define MEM(x)
Definition debug.h:36
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:260
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
Definition dlist.h:486
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition dlist.h:638
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition dlist.h:378
talloc_free(reap)
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
Definition log.c:583
fr_log_type_t
Definition log.h:54
unsigned char uint8_t
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:80
Definition log.h:96
void radius_track_state_log(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line, radius_track_t *tt, radius_track_log_extra_t extra)
Print out the state of every tracking entry.
Definition track.c:294
int radius_track_entry_update(radius_track_entry_t *te, uint8_t const *vector)
Update a tracking entry with the authentication vector.
Definition track.c:219
radius_track_entry_t * radius_track_entry_find(radius_track_t *tt, uint8_t packet_id, uint8_t const *vector)
Find a tracking entry from a request authenticator.
Definition track.c:248
int _radius_track_entry_reserve(char const *file, int line, radius_track_entry_t **te_out, TALLOC_CTX *ctx, radius_track_t *tt, request_t *request, uint8_t code, void *uctx)
Allocate a tracking entry.
Definition track.c:93
int _radius_track_entry_release(char const *file, int line, radius_track_entry_t **te_to_free)
Release a tracking entry.
Definition track.c:170
static int _radius_track_entry_release_on_free(radius_track_entry_t ***te_p)
Ensures the entry is released when the ctx passed to radius_track_entry_reserve is freed.
Definition track.c:68
radius_track_t * radius_track_alloc(TALLOC_CTX *ctx)
Create an radius_track_t.
Definition track.c:41
char const * file
Where the entry was allocated.
Definition track.h:59
fr_dlist_head_t free_list
so we allocate by least recently used
Definition track.h:67
radius_track_t * tt
Definition track.h:39
#define radius_track_entry_release(_te)
Definition track.h:90
void * uctx
Result/resumption context.
Definition track.h:47
int line
Where the entry was freed.
Definition track.h:60
uint8_t id
our ID
Definition track.h:50
uint64_t operation
Incremented each alloc and de-alloc.
Definition track.h:72
unsigned int num_requests
number of requests in the allocation
Definition track.h:65
uint8_t code
packet code (sigh)
Definition track.h:49
radius_track_entry_t id[UINT8_MAX+1]
which ID was used
Definition track.h:69
#define radius_track_entry_reserve(_te_out, _ctx, _tt, _request, _code, _uctx)
Definition track.h:82
void(* radius_track_log_extra_t)(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line, radius_track_entry_t *te)
Definition track.h:95
uint64_t operation
Used to give an idea of the alloc/free timeline.
Definition track.h:58
request_t * request
as always...
Definition track.h:45
radius_track_entry_t *** binding
Binding chunk we use to release the entry when its parent is freed.
Definition track.h:41
Track one request to a response.
Definition track.h:36
#define fr_strerror_const(_msg)
Definition strerror.h:223