limit the size of a PB-TNC batch to the maximum EAP-TNC packet size

This commit is contained in:
Andreas Steffen
2012-07-11 17:09:05 +02:00
parent 6067233193
commit 3a16bec8f9
10 changed files with 135 additions and 89 deletions
@@ -51,7 +51,6 @@ typedef struct private_pb_tnc_batch_t private_pb_tnc_batch_t;
#define PB_TNC_BATCH_FLAG_NONE 0x00 #define PB_TNC_BATCH_FLAG_NONE 0x00
#define PB_TNC_BATCH_FLAG_D (1<<7) #define PB_TNC_BATCH_FLAG_D (1<<7)
#define PB_TNC_BATCH_HEADER_SIZE 8
/** /**
* PB-TNC Message (see section 4.2 of RFC 5793) * PB-TNC Message (see section 4.2 of RFC 5793)
@@ -71,7 +70,6 @@ typedef struct private_pb_tnc_batch_t private_pb_tnc_batch_t;
#define PB_TNC_FLAG_NONE 0x00 #define PB_TNC_FLAG_NONE 0x00
#define PB_TNC_FLAG_NOSKIP (1<<7) #define PB_TNC_FLAG_NOSKIP (1<<7)
#define PB_TNC_HEADER_SIZE 12
#define PB_TNC_RESERVED_MSG_TYPE 0xffffffff #define PB_TNC_RESERVED_MSG_TYPE 0xffffffff
@@ -151,7 +149,6 @@ METHOD(pb_tnc_batch_t, build, void,
enumerator = this->messages->create_enumerator(this->messages); enumerator = this->messages->create_enumerator(this->messages);
while (enumerator->enumerate(enumerator, &msg)) while (enumerator->enumerate(enumerator, &msg))
{ {
msg->build(msg);
msg_value = msg->get_encoding(msg); msg_value = msg->get_encoding(msg);
batch_len += PB_TNC_HEADER_SIZE + msg_value.len; batch_len += PB_TNC_HEADER_SIZE + msg_value.len;
} }
@@ -29,10 +29,14 @@ typedef struct pb_tnc_batch_t pb_tnc_batch_t;
#include <library.h> #include <library.h>
#define PB_TNC_BATCH_HEADER_SIZE 8
#define PB_TNC_HEADER_SIZE 12
/** /**
* PB-TNC Batch Types as defined in section 4.1 of RFC 5793 * PB-TNC Batch Types as defined in section 4.1 of RFC 5793
*/ */
enum pb_tnc_batch_type_t { enum pb_tnc_batch_type_t {
PB_BATCH_NONE = 0, /* for internal use only */
PB_BATCH_CDATA = 1, PB_BATCH_CDATA = 1,
PB_BATCH_SDATA = 2, PB_BATCH_SDATA = 2,
PB_BATCH_RESULT = 3, PB_BATCH_RESULT = 3,
@@ -82,11 +82,13 @@ METHOD(pb_tnc_msg_t, build, void,
{ {
bio_writer_t *writer; bio_writer_t *writer;
/* build message */ if (this->encoding.ptr)
{
return;
}
writer = bio_writer_create(ACCESS_RECOMMENDATION_MSG_SIZE); writer = bio_writer_create(ACCESS_RECOMMENDATION_MSG_SIZE);
writer->write_uint16(writer, ACCESS_RECOMMENDATION_RESERVED); writer->write_uint16(writer, ACCESS_RECOMMENDATION_RESERVED);
writer->write_uint16(writer, this->recommendation); writer->write_uint16(writer, this->recommendation);
free(this->encoding.ptr);
this->encoding = writer->get_buf(writer); this->encoding = writer->get_buf(writer);
this->encoding = chunk_clone(this->encoding); this->encoding = chunk_clone(this->encoding);
writer->destroy(writer); writer->destroy(writer);
@@ -98,7 +100,6 @@ METHOD(pb_tnc_msg_t, process, status_t,
bio_reader_t *reader; bio_reader_t *reader;
u_int16_t reserved; u_int16_t reserved;
/* process message */
reader = bio_reader_create(this->encoding); reader = bio_reader_create(this->encoding);
reader->read_uint16(reader, &reserved); reader->read_uint16(reader, &reserved);
reader->read_uint16(reader, &this->recommendation); reader->read_uint16(reader, &this->recommendation);
@@ -78,10 +78,12 @@ METHOD(pb_tnc_msg_t, build, void,
{ {
bio_writer_t *writer; bio_writer_t *writer;
/* build message */ if (this->encoding.ptr)
{
return;
}
writer = bio_writer_create(ASSESSMENT_RESULT_MSG_SIZE); writer = bio_writer_create(ASSESSMENT_RESULT_MSG_SIZE);
writer->write_uint32(writer, this->assessment_result); writer->write_uint32(writer, this->assessment_result);
free(this->encoding.ptr);
this->encoding = writer->get_buf(writer); this->encoding = writer->get_buf(writer);
this->encoding = chunk_clone(this->encoding); this->encoding = chunk_clone(this->encoding);
writer->destroy(writer); writer->destroy(writer);
@@ -92,7 +94,6 @@ METHOD(pb_tnc_msg_t, process, status_t,
{ {
bio_reader_t *reader; bio_reader_t *reader;
/* process message */
reader = bio_reader_create(this->encoding); reader = bio_reader_create(this->encoding);
reader->read_uint32(reader, &this->assessment_result); reader->read_uint32(reader, &this->assessment_result);
reader->destroy(reader); reader->destroy(reader);
@@ -120,6 +120,11 @@ METHOD(pb_tnc_msg_t, build, void,
{ {
bio_writer_t *writer; bio_writer_t *writer;
if (this->encoding.ptr)
{
return;
}
/* build message header */ /* build message header */
writer = bio_writer_create(ERROR_HEADER_SIZE); writer = bio_writer_create(ERROR_HEADER_SIZE);
writer->write_uint8 (writer, this->fatal ? writer->write_uint8 (writer, this->fatal ?
@@ -142,8 +147,6 @@ METHOD(pb_tnc_msg_t, build, void,
/* Error Offset */ /* Error Offset */
writer->write_uint32(writer, this->error_offset); writer->write_uint32(writer, this->error_offset);
} }
free(this->encoding.ptr);
this->encoding = writer->get_buf(writer); this->encoding = writer->get_buf(writer);
this->encoding = chunk_clone(this->encoding); this->encoding = chunk_clone(this->encoding);
writer->destroy(writer); writer->destroy(writer);
@@ -75,6 +75,10 @@ METHOD(pb_tnc_msg_t, get_encoding, chunk_t,
METHOD(pb_tnc_msg_t, build, void, METHOD(pb_tnc_msg_t, build, void,
private_pb_language_preference_msg_t *this) private_pb_language_preference_msg_t *this)
{ {
if (this->encoding.ptr)
{
return;
}
this->encoding = chunk_cat("cc", this->encoding = chunk_cat("cc",
chunk_create(PB_LANG_PREFIX, PB_LANG_PREFIX_LEN), chunk_create(PB_LANG_PREFIX, PB_LANG_PREFIX_LEN),
this->language_preference); this->language_preference);
@@ -116,6 +116,11 @@ METHOD(pb_tnc_msg_t, build, void,
chunk_t msg_header; chunk_t msg_header;
bio_writer_t *writer; bio_writer_t *writer;
if (this->encoding.ptr)
{
return;
}
/* build message header */ /* build message header */
writer = bio_writer_create(64); writer = bio_writer_create(64);
writer->write_uint8 (writer, this->excl ? PA_FLAG_EXCL : PA_FLAG_NONE); writer->write_uint8 (writer, this->excl ? PA_FLAG_EXCL : PA_FLAG_NONE);
@@ -126,7 +131,6 @@ METHOD(pb_tnc_msg_t, build, void,
msg_header = writer->get_buf(writer); msg_header = writer->get_buf(writer);
/* create encoding by concatenating message header and message body */ /* create encoding by concatenating message header and message body */
free(this->encoding.ptr);
this->encoding = chunk_cat("cc", msg_header, this->msg_body); this->encoding = chunk_cat("cc", msg_header, this->msg_body);
writer->destroy(writer); writer->destroy(writer);
} }
@@ -83,12 +83,14 @@ METHOD(pb_tnc_msg_t, build, void,
{ {
bio_writer_t *writer; bio_writer_t *writer;
/* build message */ if (this->encoding.ptr)
{
return;
}
writer = bio_writer_create(64); writer = bio_writer_create(64);
writer->write_data32(writer, this->reason_string); writer->write_data32(writer, this->reason_string);
writer->write_data8 (writer, this->language_code); writer->write_data8 (writer, this->language_code);
free(this->encoding.ptr);
this->encoding = writer->get_buf(writer); this->encoding = writer->get_buf(writer);
this->encoding = chunk_clone(this->encoding); this->encoding = chunk_clone(this->encoding);
writer->destroy(writer); writer->destroy(writer);
@@ -99,7 +101,6 @@ METHOD(pb_tnc_msg_t, process, status_t,
{ {
bio_reader_t *reader; bio_reader_t *reader;
/* process message */
reader = bio_reader_create(this->encoding); reader = bio_reader_create(this->encoding);
if (!reader->read_data32(reader, &this->reason_string)) if (!reader->read_data32(reader, &this->reason_string))
{ {
@@ -108,14 +108,16 @@ METHOD(pb_tnc_msg_t, build, void,
{ {
bio_writer_t *writer; bio_writer_t *writer;
/* build message */ if (this->encoding.ptr)
{
return;
}
writer = bio_writer_create(64); writer = bio_writer_create(64);
writer->write_uint32(writer, this->vendor_id); writer->write_uint32(writer, this->vendor_id);
writer->write_uint32(writer, this->parameters_type); writer->write_uint32(writer, this->parameters_type);
writer->write_data32(writer, this->remediation_string); writer->write_data32(writer, this->remediation_string);
writer->write_data8 (writer, this->language_code); writer->write_data8 (writer, this->language_code);
free(this->encoding.ptr);
this->encoding = writer->get_buf(writer); this->encoding = writer->get_buf(writer);
this->encoding = chunk_clone(this->encoding); this->encoding = chunk_clone(this->encoding);
writer->destroy(writer); writer->destroy(writer);
+101 -72
View File
@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2010 Sansar Choinyanbuu * Copyright (C) 2010 Sansar Choinyanbuu
* Copyright (C) 2010-2011 Andreas Steffen * Copyright (C) 2010-2012 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil * HSR Hochschule fuer Technik Rapperswil
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@@ -36,6 +36,7 @@
#include <debug.h> #include <debug.h>
#include <threading/mutex.h> #include <threading/mutex.h>
#include <utils/linked_list.h>
#include <pen/pen.h> #include <pen/pen.h>
typedef struct private_tnccs_20_t private_tnccs_20_t; typedef struct private_tnccs_20_t private_tnccs_20_t;
@@ -66,9 +67,14 @@ struct private_tnccs_20_t {
TNC_ConnectionID connection_id; TNC_ConnectionID connection_id;
/** /**
* PB-TNC batch being constructed * PB-TNC messages to be sent
*/ */
pb_tnc_batch_t *batch; linked_list_t *messages;
/**
* Type of PB-TNC batch being constructed
*/
pb_tnc_batch_type_t batch_type;
/** /**
* Mutex locking the batch in construction * Mutex locking the batch in construction
@@ -97,6 +103,30 @@ struct private_tnccs_20_t {
}; };
/**
* If the batch type changes then delete all accumulated PB-TNC messages
*/
void change_batch_type(private_tnccs_20_t *this, pb_tnc_batch_type_t batch_type)
{
pb_tnc_msg_t *msg;
if (batch_type != this->batch_type)
{
if (this->batch_type != PB_BATCH_NONE)
{
DBG1(DBG_TNC, "cancelling PB-TNC %N batch",
pb_tnc_batch_type_names, this->batch_type);
while (this->messages->remove_last(this->messages,
(void**)&msg) == SUCCESS)
{
msg->destroy(msg);
}
}
this->batch_type = batch_type;
}
}
METHOD(tnccs_t, send_msg, TNC_Result, METHOD(tnccs_t, send_msg, TNC_Result,
private_tnccs_20_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id, private_tnccs_20_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id,
TNC_UInt32 msg_flags, TNC_UInt32 msg_flags,
@@ -138,13 +168,13 @@ METHOD(tnccs_t, send_msg, TNC_Result,
/* adding PA message to SDATA or CDATA batch only */ /* adding PA message to SDATA or CDATA batch only */
batch_type = this->is_server ? PB_BATCH_SDATA : PB_BATCH_CDATA; batch_type = this->is_server ? PB_BATCH_SDATA : PB_BATCH_CDATA;
this->mutex->lock(this->mutex); this->mutex->lock(this->mutex);
if (!this->batch) if (this->batch_type == PB_BATCH_NONE)
{ {
this->batch = pb_tnc_batch_create(this->is_server, batch_type); this->batch_type = batch_type;
} }
if (this->batch->get_type(this->batch) == batch_type) if (this->batch_type == batch_type)
{ {
this->batch->add_msg(this->batch, pb_tnc_msg); this->messages->insert_last(this->messages, pb_tnc_msg);
} }
else else
{ {
@@ -344,23 +374,19 @@ static void build_retry_batch(private_tnccs_20_t *this)
pb_tnc_batch_type_t batch_retry_type; pb_tnc_batch_type_t batch_retry_type;
batch_retry_type = this->is_server ? PB_BATCH_SRETRY : PB_BATCH_CRETRY; batch_retry_type = this->is_server ? PB_BATCH_SRETRY : PB_BATCH_CRETRY;
if (this->batch) if (this->batch_type == batch_retry_type)
{ {
if (this->batch->get_type(this->batch) == batch_retry_type) /* retry batch has already been selected */
{ return;
/* retry batch has already been created */ }
return;
} change_batch_type(this, batch_retry_type);
DBG1(DBG_TNC, "cancelling PB-TNC %N batch",
pb_tnc_batch_type_names, this->batch->get_type(this->batch));
this->batch->destroy(this->batch);
}
if (this->is_server) if (this->is_server)
{ {
tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id, tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id,
TNC_CONNECTION_STATE_HANDSHAKE); TNC_CONNECTION_STATE_HANDSHAKE);
} }
this->batch = pb_tnc_batch_create(this->is_server, batch_retry_type);
} }
METHOD(tls_t, process, status_t, METHOD(tls_t, process, status_t,
@@ -461,13 +487,7 @@ METHOD(tls_t, process, status_t,
case FAILED: case FAILED:
this->fatal_error = TRUE; this->fatal_error = TRUE;
this->mutex->lock(this->mutex); this->mutex->lock(this->mutex);
if (this->batch) change_batch_type(this, PB_BATCH_CLOSE);
{
DBG1(DBG_TNC, "cancelling PB-TNC %N batch",
pb_tnc_batch_type_names, this->batch->get_type(this->batch));
this->batch->destroy(this->batch);
}
this->batch = pb_tnc_batch_create(this->is_server, PB_BATCH_CLOSE);
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);
/* fall through to add error messages to outbound batch */ /* fall through to add error messages to outbound batch */
case VERIFY_ERROR: case VERIFY_ERROR:
@@ -475,7 +495,7 @@ METHOD(tls_t, process, status_t,
while (enumerator->enumerate(enumerator, &msg)) while (enumerator->enumerate(enumerator, &msg))
{ {
this->mutex->lock(this->mutex); this->mutex->lock(this->mutex);
this->batch->add_msg(this->batch, msg->get_ref(msg)); this->messages->insert_last(this->messages, msg->get_ref(msg));
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
@@ -508,10 +528,10 @@ static void check_and_build_recommendation(private_tnccs_20_t *this)
} }
if (this->recs->have_recommendation(this->recs, &rec, &eval)) if (this->recs->have_recommendation(this->recs, &rec, &eval))
{ {
this->batch = pb_tnc_batch_create(this->is_server, PB_BATCH_RESULT); this->batch_type = PB_BATCH_RESULT;
msg = pb_assessment_result_msg_create(eval); msg = pb_assessment_result_msg_create(eval);
this->batch->add_msg(this->batch, msg); this->messages->insert_last(this->messages, msg);
/** /**
* Map IMV Action Recommendation codes to PB Access Recommendation codes * Map IMV Action Recommendation codes to PB Access Recommendation codes
@@ -530,13 +550,13 @@ static void check_and_build_recommendation(private_tnccs_20_t *this)
pb_rec = PB_REC_ACCESS_DENIED; pb_rec = PB_REC_ACCESS_DENIED;
} }
msg = pb_access_recommendation_msg_create(pb_rec); msg = pb_access_recommendation_msg_create(pb_rec);
this->batch->add_msg(this->batch, msg); this->messages->insert_last(this->messages, msg);
enumerator = this->recs->create_reason_enumerator(this->recs); enumerator = this->recs->create_reason_enumerator(this->recs);
while (enumerator->enumerate(enumerator, &id, &reason, &language)) while (enumerator->enumerate(enumerator, &id, &reason, &language))
{ {
msg = pb_reason_string_msg_create(reason, language); msg = pb_reason_string_msg_create(reason, language);
this->batch->add_msg(this->batch, msg); this->messages->insert_last(this->messages, msg);
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
this->recs->clear_reasons(this->recs); this->recs->clear_reasons(this->recs);
@@ -568,8 +588,8 @@ METHOD(tls_t, build, status_t,
msg = pb_language_preference_msg_create(chunk_create(pref_lang, msg = pb_language_preference_msg_create(chunk_create(pref_lang,
strlen(pref_lang))); strlen(pref_lang)));
this->mutex->lock(this->mutex); this->mutex->lock(this->mutex);
this->batch = pb_tnc_batch_create(this->is_server, PB_BATCH_CDATA); this->batch_type = PB_BATCH_CDATA;
this->batch->add_msg(this->batch, msg); this->messages->insert_last(this->messages, msg);
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);
tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id, tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id,
@@ -603,66 +623,73 @@ METHOD(tls_t, build, status_t,
this->request_handshake_retry = FALSE; this->request_handshake_retry = FALSE;
} }
if (!this->batch) if (this->batch_type == PB_BATCH_NONE && this->is_server &&
state == PB_STATE_SERVER_WORKING)
{ {
if (this->is_server) check_and_build_recommendation(this);
{
if (state == PB_STATE_SERVER_WORKING)
{
check_and_build_recommendation(this);
}
}
else
{
/**
* if the DECIDED state has been reached and no CRETRY is under way
* or if a CLOSE batch with error messages has been received,
* a PB-TNC client replies with an empty CLOSE batch.
*/
if (state == PB_STATE_DECIDED || state == PB_STATE_END)
{
this->batch = pb_tnc_batch_create(this->is_server, PB_BATCH_CLOSE);
}
}
} }
if (this->batch) if (this->batch_type != PB_BATCH_NONE)
{ {
pb_tnc_batch_type_t batch_type; pb_tnc_batch_t *batch;
chunk_t data; pb_tnc_msg_t *msg;
chunk_t msg_value, data;
int msg_count;
size_t batch_len;
enumerator_t *enumerator;
batch_type = this->batch->get_type(this->batch); if (this->state_machine->send_batch(this->state_machine, this->batch_type))
if (this->state_machine->send_batch(this->state_machine, batch_type))
{ {
this->batch->build(this->batch); batch = pb_tnc_batch_create(this->is_server, this->batch_type);
data = this->batch->get_encoding(this->batch); batch_len = PB_TNC_BATCH_HEADER_SIZE;
enumerator = this->messages->create_enumerator(this->messages);
while (enumerator->enumerate(enumerator, &msg))
{
msg->build(msg);
msg_value = msg->get_encoding(msg);
batch_len += PB_TNC_HEADER_SIZE + msg_value.len;
if (batch_len > *buflen)
{
/* message does not fit into batch of maximum size */
break;
}
batch->add_msg(batch, msg);
this->messages->remove_at(this->messages, enumerator);
}
enumerator->destroy(enumerator);
batch->build(batch);
data = batch->get_encoding(batch);
DBG1(DBG_TNC, "sending PB-TNC %N batch (%d bytes) for Connection ID %u", DBG1(DBG_TNC, "sending PB-TNC %N batch (%d bytes) for Connection ID %u",
pb_tnc_batch_type_names, batch_type, data.len, pb_tnc_batch_type_names, this->batch_type, data.len,
this->connection_id); this->connection_id);
DBG3(DBG_TNC, "%B", &data); DBG3(DBG_TNC, "%B", &data);
*msglen = 0;
if (data.len > *buflen) *buflen = data.len;
*msglen = 0;
memcpy(buf, data.ptr, *buflen);
batch->destroy(batch);
msg_count = this->messages->get_count(this->messages);
if (msg_count)
{ {
DBG1(DBG_TNC, "fragmentation of PB-TNC batch not supported yet"); DBG2(DBG_TNC, "%d PB-TNC message%s for %N batch queued",
msg_count, (msg_count == 1) ? "" : "s",
pb_tnc_batch_type_names, this->batch_type);
} }
else else
{ {
*buflen = data.len; this->batch_type = PB_BATCH_NONE;
} }
memcpy(buf, data.ptr, *buflen);
status = ALREADY_DONE; status = ALREADY_DONE;
} }
else else
{ {
DBG1(DBG_TNC, "cancelling unexpected PB-TNC batch type: %N", change_batch_type(this, PB_BATCH_NONE);
pb_tnc_batch_type_names, batch_type);
status = INVALID_STATE; status = INVALID_STATE;
} }
this->batch->destroy(this->batch);
this->batch = NULL;
} }
else else
{ {
@@ -715,7 +742,8 @@ METHOD(tls_t, destroy, void,
this->is_server); this->is_server);
this->state_machine->destroy(this->state_machine); this->state_machine->destroy(this->state_machine);
this->mutex->destroy(this->mutex); this->mutex->destroy(this->mutex);
DESTROY_IF(this->batch); this->messages->destroy_offset(this->messages,
offsetof(pb_tnc_msg_t, destroy));
free(this); free(this);
} }
@@ -739,6 +767,7 @@ tls_t *tnccs_20_create(bool is_server)
.is_server = is_server, .is_server = is_server,
.state_machine = pb_tnc_state_machine_create(is_server), .state_machine = pb_tnc_state_machine_create(is_server),
.mutex = mutex_create(MUTEX_TYPE_DEFAULT), .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
.messages = linked_list_create(),
); );
return &this->public; return &this->public;