Detect RADIUS packet retransmissions

This commit is contained in:
Andreas Steffen
2014-05-31 20:37:57 +02:00
parent bfd8f8c5fe
commit 59db666094
+89 -2
View File
@@ -18,6 +18,7 @@
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <radius_message.h>
#include <radius_mppe.h>
@@ -37,7 +38,7 @@
#include <sa/eap/eap_method.h>
typedef struct private_tnc_pdp_t private_tnc_pdp_t;
typedef struct client_entry_t client_entry_t;
/**
* Default RADIUS port, when not configured
*/
@@ -48,6 +49,8 @@ typedef struct private_tnc_pdp_t private_tnc_pdp_t;
*/
#define MAX_PACKET 4096
#define RADIUS_RETRANSMIT_TIMEOUT 30 /* seconds */
/**
* private data of tnc_pdp_t
*/
@@ -98,6 +101,11 @@ struct private_tnc_pdp_t {
*/
chunk_t secret;
/**
* RADIUS clients
*/
linked_list_t *clients;
/**
* MD5 hasher
*/
@@ -120,6 +128,33 @@ struct private_tnc_pdp_t {
};
/**
* Client entry helping to detect RADIUS packet retransmissions
*/
struct client_entry_t {
/**
* IP host address and port of client
*/
host_t *host;
/**
* Time of last RADIUS Access-Request received from client
*/
time_t last_time;
/**
* Identifier of last RADIUS Access-Request received from client
*/
uint8_t last_id;
};
static void free_client_entry(client_entry_t *this)
{
this->host->destroy(this->host);
free(this);
}
/**
* Open IPv4 or IPv6 UDP socket
*/
@@ -663,16 +698,24 @@ static bool radius_receive(private_tnc_pdp_t *this, int fd, watcher_event_t even
{
radius_message_t *request;
char buffer[MAX_PACKET];
client_entry_t *client;
bool retransmission = FALSE, found = FALSE, stale;
enumerator_t *enumerator;
int bytes_read = 0;
host_t *source;
uint8_t id;
time_t now;
union {
struct sockaddr_in in4;
struct sockaddr_in6 in6;
} src;
struct iovec iov = {
.iov_base = buffer,
.iov_len = MAX_PACKET,
};
struct msghdr msg = {
.msg_name = &src,
.msg_namelen = sizeof(src),
@@ -704,7 +747,46 @@ static bool radius_receive(private_tnc_pdp_t *this, int fd, watcher_event_t even
if (request->verify(request, NULL, this->secret, this->hasher,
this->signer))
{
process_eap(this, request, source);
id = request->get_identifier(request);
now = time(NULL);
enumerator = this->clients->create_enumerator(this->clients);
while (enumerator->enumerate(enumerator, &client))
{
stale = client->last_time < now - RADIUS_RETRANSMIT_TIMEOUT;
if (source->equals(source, client->host))
{
retransmission = !stale && client->last_id == id;
client->last_id = id;
client->last_time = now;
found = TRUE;
}
else if (stale)
{
this->clients->remove_at(this->clients, enumerator);
free_client_entry(client);
}
}
enumerator->destroy(enumerator);
if (!found)
{
client = malloc_thing(client_entry_t);
client->host = source->clone(source);
client->last_id = id;
client->last_time = now;
this->clients->insert_last(this->clients, client);
}
if (retransmission)
{
DBG1(DBG_CFG, "ignoring RADIUS Access-Request 0x%02x, "
"already processing", id);
}
else
{
process_eap(this, request, source);
}
}
request->destroy(request);
}
@@ -739,6 +821,10 @@ METHOD(tnc_pdp_t, destroy, void,
lib->watcher->remove(lib->watcher, this->radius_ipv6);
close(this->radius_ipv6);
}
if (this->clients)
{
this->clients->destroy_function(this->clients, (void*)free_client_entry);
}
DESTROY_IF(this->server);
DESTROY_IF(this->signer);
DESTROY_IF(this->hasher);
@@ -843,6 +929,7 @@ tnc_pdp_t *tnc_pdp_create(void)
this->radius_ipv4 = open_udp_socket(AF_INET, radius_port);
this->radius_ipv6 = open_udp_socket(AF_INET6, radius_port);
this->secret = chunk_from_str(secret);
this->clients = linked_list_create();
this->type = eap_type_from_string(eap_type_str);
this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128);