From: Alan T. DeKok Date: Sun, 20 Nov 2016 02:49:39 +0000 (-0500) Subject: Simple RADIUS packet tracking API X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1600b51aa2a32cbc65a44743bc9fdcdb8806ac07;p=thirdparty%2Ffreeradius-server.git Simple RADIUS packet tracking API --- diff --git a/src/util/all.mk b/src/util/all.mk index 97fe97b80f7..4a918beceec 100644 --- a/src/util/all.mk +++ b/src/util/all.mk @@ -1,6 +1,6 @@ TARGET := libfreeradius-util.a -SOURCES := ring_buffer.c message.c atomic_queue.c queue.c time.c channel.c +SOURCES := ring_buffer.c message.c atomic_queue.c queue.c time.c channel.c track.c TGT_PREREQS := libfreeradius-radius.la TGT_LDLIBS := $(LIBS) diff --git a/src/util/track.c b/src/util/track.c new file mode 100644 index 00000000000..2f1e835deff --- /dev/null +++ b/src/util/track.c @@ -0,0 +1,142 @@ +/* + * track.c RADIUS packet tracking + * + * Version: $Id$ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Copyright 2016 Alan DeKok + */ +RCSID("$Id$") + +#include + +/* + * RADIUS-specific tracking table. + * + * It's a fixed-size array of 256 entries, indexed by ID. Which + * means we don't need to store ID in the table. We also don't + * need to store the packet type, as we assume that we have a + * unique tracking table per packet type. + */ + +struct fr_tracking_t { + int num_entries; //!< number of used entries. + + fr_tracking_entry_t packet[256]; +}; + +/** Create a tracking table for one type of RADIUS packets. + * + * @param[in] ctx the talloc ctx + * @return + * - NULL on error + * - fr_tracking_t * on success + */ +fr_tracking_t *fr_radius_tracking_create(TALLOC_CTX *ctx) +{ + fr_tracking_t *ft; + + if (!ctx) return NULL; + + ft = talloc_zero(ctx, fr_tracking_t); + if (!ft) return NULL; + + ft->num_entries = 0; + return ft; +} + +/** Delete an entry from the tracking table. + * + * @param[in] ft the tracking table + * @param[in] id the ID of the entry to delete + * @return + * - <0 on error + * - 0 on success + */ +int fr_radius_tracking_entry_delete(fr_tracking_t *ft, uint8_t id) +{ + fr_tracking_entry_t *entry; + +#ifndef NDEBUG + (void) talloc_get_type_abort(ft, fr_tracking_t); +#endif + entry = &ft->packet[id]; + if (entry->timestamp == 0) return -1; + + entry->timestamp = 0; + ft->num_entries--; + + return 0; +} + +/** Insert a (possibly new) packet and a timestamp + * + * @param[in] ft the tracking table + * @param[in] packet the RADIUS packet to insert + * @param[in] timestamp when this packet was received + * @param[out] p_entry pointer to newly inserted entry. + * @return + * - FR_TRACKING_UNUSED, there was an error inserting the element + * - FR_TRACKING_NEW, a new entry was created + * - FR_TRACKING_SAME, the packet is the same as one already in the tracking table + * - FR_TRACKING_DIFFERENT, the old packet was deleted, and the newer packet inserted + */ +fr_tracking_status_t fr_radius_tracking_entry_insert(fr_tracking_t *ft, uint8_t *packet, fr_time_t timestamp, + fr_tracking_entry_t **p_entry) +{ + fr_tracking_entry_t *entry; + +#ifndef NDEBUG + (void) talloc_get_type_abort(ft, fr_tracking_t); +#endif + + entry = &ft->packet[packet[1]]; + + /* + * The entry is unused, insert it. + */ + if (entry->timestamp == 0) { + entry->timestamp = timestamp; + memcpy(&entry->data[0], packet + 2, 18); + *p_entry = entry; + + ft->num_entries++; + return FR_TRACKING_NEW; + } + + /* + * Is it the same packet? If so, return that. + */ + if (memcmp(packet + 2, &entry->data[0], 18) == 0) { + *p_entry = entry; + return FR_TRACKING_SAME; + } + + /* + * It's in use, but the new packet is different. update + * the timestamp, so that anyone checking it knows it's + * no longer relevant. + */ + entry->timestamp = timestamp; + + /* + * Copy the new packet over top of the old one. + */ + memcpy(&entry->data[0], packet + 2, 18); + *p_entry = entry; + + return FR_TRACKING_DIFFERENT; +} diff --git a/src/util/track.h b/src/util/track.h new file mode 100644 index 00000000000..b75032ec29a --- /dev/null +++ b/src/util/track.h @@ -0,0 +1,65 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef _FR_TRACK_H +#define _FR_TRACK_H +/** + * $Id$ + * + * @file util/track.h + * @brief RADIUS packet tracking. + * + * @copyright 2016 Alan DeKok + */ +RCSIDH(track_h, "$Id$") + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct fr_tracking_t fr_tracking_t; + +/** + * An entry for the tracking table. It contains the minimum + * information required to track RADIUS packets. + */ +typedef struct fr_tracking_entry_t { + fr_time_t timestamp; //!< when received + uint8_t data[18]; //!< 2 byte length + authentication vector +} fr_tracking_entry_t; + +/** + * The status of an insert. + */ +typedef enum fr_tracking_status_t { + FR_TRACKING_UNUSED = 0, + FR_TRACKING_NEW, + FR_TRACKING_SAME, + FR_TRACKING_DIFFERENT, +} fr_tracking_status_t; + +fr_tracking_t *fr_radius_tracking_create(TALLOC_CTX *ctx); +int fr_radius_tracking_entry_delete(fr_tracking_t *ft, uint8_t id) CC_HINT(nonnull); +fr_tracking_status_t fr_radius_tracking_entry_insert(fr_tracking_t *ft, uint8_t *packet, fr_time_t timestamp, + fr_tracking_entry_t **p_entry) CC_HINT(nonnull); + +#ifdef __cplusplus +} +#endif + +#endif /* _FR_TRACK_H */