From: Andreas Steffen Date: Tue, 10 Jul 2012 20:51:49 +0000 (+0200) Subject: limit the size of a PB-TNC batch to the maximum EAP-TNC packet size X-Git-Tag: 5.0.1~424 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3a16bec8f9b2c32e503aca257337ce484ad5633f;p=thirdparty%2Fstrongswan.git limit the size of a PB-TNC batch to the maximum EAP-TNC packet size --- diff --git a/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.c b/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.c index c6a4bb5998..523ca0d0ce 100644 --- a/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.c +++ b/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.c @@ -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_D (1<<7) -#define PB_TNC_BATCH_HEADER_SIZE 8 /** * 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_NOSKIP (1<<7) -#define PB_TNC_HEADER_SIZE 12 #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); while (enumerator->enumerate(enumerator, &msg)) { - msg->build(msg); msg_value = msg->get_encoding(msg); batch_len += PB_TNC_HEADER_SIZE + msg_value.len; } diff --git a/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.h b/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.h index 17e5fff4c6..8d91c13164 100644 --- a/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.h +++ b/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.h @@ -29,10 +29,14 @@ typedef struct pb_tnc_batch_t pb_tnc_batch_t; #include +#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 */ enum pb_tnc_batch_type_t { + PB_BATCH_NONE = 0, /* for internal use only */ PB_BATCH_CDATA = 1, PB_BATCH_SDATA = 2, PB_BATCH_RESULT = 3, diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_access_recommendation_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_access_recommendation_msg.c index fa3deddf66..974db4d709 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_access_recommendation_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_access_recommendation_msg.c @@ -82,11 +82,13 @@ METHOD(pb_tnc_msg_t, build, void, { bio_writer_t *writer; - /* build message */ + if (this->encoding.ptr) + { + return; + } writer = bio_writer_create(ACCESS_RECOMMENDATION_MSG_SIZE); writer->write_uint16(writer, ACCESS_RECOMMENDATION_RESERVED); writer->write_uint16(writer, this->recommendation); - free(this->encoding.ptr); this->encoding = writer->get_buf(writer); this->encoding = chunk_clone(this->encoding); writer->destroy(writer); @@ -98,7 +100,6 @@ METHOD(pb_tnc_msg_t, process, status_t, bio_reader_t *reader; u_int16_t reserved; - /* process message */ reader = bio_reader_create(this->encoding); reader->read_uint16(reader, &reserved); reader->read_uint16(reader, &this->recommendation); diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_assessment_result_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_assessment_result_msg.c index 0d558c0d44..ee06575b42 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_assessment_result_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_assessment_result_msg.c @@ -78,10 +78,12 @@ METHOD(pb_tnc_msg_t, build, void, { bio_writer_t *writer; - /* build message */ + if (this->encoding.ptr) + { + return; + } writer = bio_writer_create(ASSESSMENT_RESULT_MSG_SIZE); writer->write_uint32(writer, this->assessment_result); - free(this->encoding.ptr); this->encoding = writer->get_buf(writer); this->encoding = chunk_clone(this->encoding); writer->destroy(writer); @@ -92,7 +94,6 @@ METHOD(pb_tnc_msg_t, process, status_t, { bio_reader_t *reader; - /* process message */ reader = bio_reader_create(this->encoding); reader->read_uint32(reader, &this->assessment_result); reader->destroy(reader); diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_error_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_error_msg.c index 03e3cec926..457d3da21b 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_error_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_error_msg.c @@ -120,6 +120,11 @@ METHOD(pb_tnc_msg_t, build, void, { bio_writer_t *writer; + if (this->encoding.ptr) + { + return; + } + /* build message header */ writer = bio_writer_create(ERROR_HEADER_SIZE); writer->write_uint8 (writer, this->fatal ? @@ -142,8 +147,6 @@ METHOD(pb_tnc_msg_t, build, void, /* Error Offset */ writer->write_uint32(writer, this->error_offset); } - - free(this->encoding.ptr); this->encoding = writer->get_buf(writer); this->encoding = chunk_clone(this->encoding); writer->destroy(writer); diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_language_preference_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_language_preference_msg.c index 297cc8df74..46df544867 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_language_preference_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_language_preference_msg.c @@ -75,6 +75,10 @@ METHOD(pb_tnc_msg_t, get_encoding, chunk_t, METHOD(pb_tnc_msg_t, build, void, private_pb_language_preference_msg_t *this) { + if (this->encoding.ptr) + { + return; + } this->encoding = chunk_cat("cc", chunk_create(PB_LANG_PREFIX, PB_LANG_PREFIX_LEN), this->language_preference); diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c index 1c4913e5e0..4d5f983c79 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c @@ -116,6 +116,11 @@ METHOD(pb_tnc_msg_t, build, void, chunk_t msg_header; bio_writer_t *writer; + if (this->encoding.ptr) + { + return; + } + /* build message header */ writer = bio_writer_create(64); 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); /* create encoding by concatenating message header and message body */ - free(this->encoding.ptr); this->encoding = chunk_cat("cc", msg_header, this->msg_body); writer->destroy(writer); } diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_reason_string_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_reason_string_msg.c index 181ecf61bb..511b454027 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_reason_string_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_reason_string_msg.c @@ -83,12 +83,14 @@ METHOD(pb_tnc_msg_t, build, void, { bio_writer_t *writer; - /* build message */ + if (this->encoding.ptr) + { + return; + } writer = bio_writer_create(64); writer->write_data32(writer, this->reason_string); writer->write_data8 (writer, this->language_code); - free(this->encoding.ptr); this->encoding = writer->get_buf(writer); this->encoding = chunk_clone(this->encoding); writer->destroy(writer); @@ -99,7 +101,6 @@ METHOD(pb_tnc_msg_t, process, status_t, { bio_reader_t *reader; - /* process message */ reader = bio_reader_create(this->encoding); if (!reader->read_data32(reader, &this->reason_string)) { diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_remediation_parameters_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_remediation_parameters_msg.c index d213db3137..c853f03a30 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_remediation_parameters_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_remediation_parameters_msg.c @@ -108,14 +108,16 @@ METHOD(pb_tnc_msg_t, build, void, { bio_writer_t *writer; - /* build message */ + if (this->encoding.ptr) + { + return; + } writer = bio_writer_create(64); writer->write_uint32(writer, this->vendor_id); writer->write_uint32(writer, this->parameters_type); writer->write_data32(writer, this->remediation_string); writer->write_data8 (writer, this->language_code); - free(this->encoding.ptr); this->encoding = writer->get_buf(writer); this->encoding = chunk_clone(this->encoding); writer->destroy(writer); diff --git a/src/libcharon/plugins/tnccs_20/tnccs_20.c b/src/libcharon/plugins/tnccs_20/tnccs_20.c index 66f2f664b8..576cd825b6 100644 --- a/src/libcharon/plugins/tnccs_20/tnccs_20.c +++ b/src/libcharon/plugins/tnccs_20/tnccs_20.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 Sansar Choinyanbuu - * Copyright (C) 2010-2011 Andreas Steffen + * Copyright (C) 2010-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ #include #include +#include #include typedef struct private_tnccs_20_t private_tnccs_20_t; @@ -66,9 +67,14 @@ struct private_tnccs_20_t { 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 @@ -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, private_tnccs_20_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id, TNC_UInt32 msg_flags, @@ -138,13 +168,13 @@ METHOD(tnccs_t, send_msg, TNC_Result, /* adding PA message to SDATA or CDATA batch only */ batch_type = this->is_server ? PB_BATCH_SDATA : PB_BATCH_CDATA; 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 { @@ -344,23 +374,19 @@ static void build_retry_batch(private_tnccs_20_t *this) pb_tnc_batch_type_t batch_retry_type; 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 created */ - return; - } - DBG1(DBG_TNC, "cancelling PB-TNC %N batch", - pb_tnc_batch_type_names, this->batch->get_type(this->batch)); - this->batch->destroy(this->batch); - } + /* retry batch has already been selected */ + return; + } + + change_batch_type(this, batch_retry_type); + if (this->is_server) { tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id, TNC_CONNECTION_STATE_HANDSHAKE); } - this->batch = pb_tnc_batch_create(this->is_server, batch_retry_type); } METHOD(tls_t, process, status_t, @@ -461,13 +487,7 @@ METHOD(tls_t, process, status_t, case FAILED: this->fatal_error = TRUE; this->mutex->lock(this->mutex); - if (this->batch) - { - 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); + change_batch_type(this, PB_BATCH_CLOSE); this->mutex->unlock(this->mutex); /* fall through to add error messages to outbound batch */ case VERIFY_ERROR: @@ -475,7 +495,7 @@ METHOD(tls_t, process, status_t, while (enumerator->enumerate(enumerator, &msg)) { 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); } 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)) { - 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); - this->batch->add_msg(this->batch, msg); + this->messages->insert_last(this->messages, msg); /** * 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; } 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); while (enumerator->enumerate(enumerator, &id, &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); 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, strlen(pref_lang))); this->mutex->lock(this->mutex); - this->batch = pb_tnc_batch_create(this->is_server, PB_BATCH_CDATA); - this->batch->add_msg(this->batch, msg); + this->batch_type = PB_BATCH_CDATA; + this->messages->insert_last(this->messages, msg); this->mutex->unlock(this->mutex); 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; } - if (!this->batch) + if (this->batch_type == PB_BATCH_NONE && this->is_server && + state == PB_STATE_SERVER_WORKING) { - if (this->is_server) - { - 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); - } - } + check_and_build_recommendation(this); } - if (this->batch) + if (this->batch_type != PB_BATCH_NONE) { - pb_tnc_batch_type_t batch_type; - chunk_t data; - - batch_type = this->batch->get_type(this->batch); + pb_tnc_batch_t *batch; + pb_tnc_msg_t *msg; + chunk_t msg_value, data; + int msg_count; + size_t batch_len; + enumerator_t *enumerator; - if (this->state_machine->send_batch(this->state_machine, batch_type)) + if (this->state_machine->send_batch(this->state_machine, this->batch_type)) { - this->batch->build(this->batch); - data = this->batch->get_encoding(this->batch); + batch = pb_tnc_batch_create(this->is_server, this->batch_type); + 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", - pb_tnc_batch_type_names, batch_type, data.len, + pb_tnc_batch_type_names, this->batch_type, data.len, this->connection_id); DBG3(DBG_TNC, "%B", &data); + + *buflen = data.len; *msglen = 0; + memcpy(buf, data.ptr, *buflen); + batch->destroy(batch); - if (data.len > *buflen) + 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 { - *buflen = data.len; + this->batch_type = PB_BATCH_NONE; } - memcpy(buf, data.ptr, *buflen); + status = ALREADY_DONE; } else { - DBG1(DBG_TNC, "cancelling unexpected PB-TNC batch type: %N", - pb_tnc_batch_type_names, batch_type); + change_batch_type(this, PB_BATCH_NONE); status = INVALID_STATE; } - - this->batch->destroy(this->batch); - this->batch = NULL; } else { @@ -715,7 +742,8 @@ METHOD(tls_t, destroy, void, this->is_server); this->state_machine->destroy(this->state_machine); this->mutex->destroy(this->mutex); - DESTROY_IF(this->batch); + this->messages->destroy_offset(this->messages, + offsetof(pb_tnc_msg_t, destroy)); free(this); } @@ -739,6 +767,7 @@ tls_t *tnccs_20_create(bool is_server) .is_server = is_server, .state_machine = pb_tnc_state_machine_create(is_server), .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .messages = linked_list_create(), ); return &this->public;