Merge pull request #69 from nickbroon/remove_data_templates

Remove data templates
master
Oliver Gasser 2017-12-11 13:35:11 +01:00 committed by GitHub
commit a1565d84a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 53 additions and 964 deletions

View File

@ -40,7 +40,6 @@ extern "C" {
#define NetflowV9_SetId_OptionsTemplate 1
#define IPFIX_SetId_Template 2
#define IPFIX_SetId_OptionsTemplate 3
#define IPFIX_SetId_DataTemplate 4
#define IPFIX_SetId_Data_Start 256
// enterprise bit

View File

@ -987,7 +987,7 @@ int ipfix_remove_template(ipfix_exporter *exporter, uint16_t template_id) {
// end of the buffer since the WITHDRAWAL message for one template is always 8 byte
p_end = p_pos + 8;
// set ID is 2 for a template, 4 for a template with fixed fields:
// set ID is 2 for a template:
// for withdrawal messages we keep the template set ID
p_pos += 2;
// write 8 to the length field
@ -998,7 +998,6 @@ int ipfix_remove_template(ipfix_exporter *exporter, uint16_t template_id) {
write_unsigned16 (&p_pos, p_end, 0);
exporter->template_arr[found_index].fields_length = 8;
exporter->template_arr[found_index].field_count = 0;
exporter->template_arr[found_index].fixedfield_count = 0;
exporter->template_arr[found_index].fields_added = 0;
exporter->template_arr[found_index].state = T_WITHDRAWN;
DPRINTFL(MSG_VDEBUG, "... Withdrawn");
@ -2389,67 +2388,29 @@ out:
/*******************************************************************/
/*!
* \brief Marks the beginning of a Data Template Set and a Template Record
* \brief Start defining a new Template (Set).
*
* ipfixlolib supports only one Data Template Record per Date Template Set. So
* this function basically starts a Data Template Set and one Data Template
* Record.
* ipfixlolib supports only one Template Record per Template Set. So this
* function basically starts a Template Set and one Template Record.
*
* Data Templates are a proprietary extension to IPFIX. See
* <tt>draft-dressler-ipfix-aggregation-00</tt> for details. Data Templates
* are like standard Templates except that they may specify fields with fixed
* values i.e. fields that share the same value for all Data Records. These
* values are transmitted once as part of the Data Template Record instead of
* repeatedly transmitting them with every Data Record.
* <em>Note:</em> It is not possible to start and define multiple Templates in parallel.
* ipfix_end_template() has to be called first before a new Template can be
* defined.
*
* A Data Template consists of (in this order):
* <ul>
* <li>Field Specifiers (like in standard Template Records)</li>
* <li>Field Specifiers of the fixed-value fields</li>
* <li>Data values of the fixed-value fields</li>
* </ul>
*
* Use the following functions to add the Field Specifiers and Data values to
* the template:
* <ul>
* <li>ipfix_put_template_field()
* <li>ipfix_put_template_fixedfield()
* <li>ipfix_put_template_data()
* </ul>
*
* <em>Note:</em> It is not possible to start and define multiple Data
* Templates in parallel. ipfix_end_template() has to be called first before a
* new Data Template can be defined.
* Individual fields are added to the Template by calling
* ipfix_put_data_field() before calling ipfix_end_template() to end the
* Template.
*
* \param exporter pointer to previously initialized exporter struct
* \param template_id ID for this Template. Must be > 255.
* \param preceding
* \param field_count number of fields that will be added to this Data Template Record.
* It is considered an error if more or fewer fields are added.
* \param fixedfield_count number of fixed-value fields that will be added to this Data Template Record.
* \param field_count number of fields that will be added to this Template Record.
* It is considered an error if more or fewer fields are added.
* \return 0 success
* \return -1 failure. Reasons include:<ul><li><tt>template_id</tt> is not
* great than 255</li><li>maximum number of defined templates has been
* exceeded</li></ul>
* \sa ipfix_end_template(), ipfix_put_template_field(), ipfix_put_template_fixedfield(), ipfix_send()
*/
/*
* Allocate memory for a new template
* end_data_template will add this template to the exporter
*/
int ipfix_start_datatemplate (ipfix_exporter *exporter,
uint16_t template_id, uint16_t preceding, uint16_t field_count,
uint16_t fixedfield_count) {
/* Is this a regular Template (Set id == 2) or a Data Template (Set id == 4).
See draft-dressler-ipfix-aggregation-00 for more details on Data Templates.
Data Templates are (still) a proprietary extension to IPFIX. */
int datatemplate=(fixedfield_count || preceding) ? 1 : 0;
if (datatemplate && (exporter->export_protocol != IPFIX_PROTOCOL)) {
msg(MSG_ERROR, "Only IPFIX supports data templates");
return -1;
}
* \return -1 failure. Reasons might be that <tt>template_id</tt> is not great than 255
* or that the maximum number of defined templates has been exceeded.
* \sa ipfix_end_template(), ipfix_put_template_field(), ipfix_send()
**/
int ipfix_start_template (ipfix_exporter *exporter, uint16_t template_id, uint16_t field_count) {
/* Make sure that template_id is > 255 */
if (!(template_id > 255)) {
msg(MSG_ERROR, "Template id has to be > 255. Start of template cancelled.");
@ -2497,17 +2458,14 @@ int ipfix_start_datatemplate (ipfix_exporter *exporter,
// field type, field length (2*2bytes)
// and an optional Enterprise Number (4 bytes)
// Also, reserve 4+4 bytes for the Set Header and the Template Record header
// In case of a Data Template, the Data Template Record header is 8 bytes long
// (instead of 4 bytes). The total overhead is 4+8=12 in this case.
exporter->template_arr[found_index].max_fields_length = 8 * (field_count + fixedfield_count) + (datatemplate ? 12 : 8);
exporter->template_arr[found_index].max_fields_length = 8 * field_count + 8;
exporter->template_arr[found_index].template_fields = (char*)malloc(exporter->template_arr[found_index].max_fields_length );
// initialize the rest:
exporter->template_arr[found_index].state = T_UNCLEAN;
exporter->template_arr[found_index].template_id = template_id;
exporter->template_arr[found_index].field_count = field_count;
exporter->template_arr[found_index].fixedfield_count = fixedfield_count;
exporter->template_arr[found_index].fields_added = 0;
// also, write the template header fields into the buffer (except the length field);
@ -2518,7 +2476,7 @@ int ipfix_start_datatemplate (ipfix_exporter *exporter,
p_end = p_pos + exporter->template_arr[found_index].max_fields_length;
// ++ Start of Set Header
// set ID is 2 for a Template Set, 4 for a Data Template with fixed fields:
// set ID is 2 for a Template Set:
// see RFC 5101: 3.3.2 Set Header Format
/// NFV9 uses 0 for Template Set ID, and does not support Data Templates
// see RFC 3954: 5.2 Template FlowSet Format
@ -2527,7 +2485,7 @@ int ipfix_start_datatemplate (ipfix_exporter *exporter,
write_unsigned16 (&p_pos, p_end, 0);
break;
case IPFIX_PROTOCOL:
write_unsigned16 (&p_pos, p_end, datatemplate ? 4 : 2);
write_unsigned16 (&p_pos, p_end, 2);
break;
default:
msg(MSG_ERROR, "Cannot write Template Set ID for unknown protocol");
@ -2543,15 +2501,9 @@ int ipfix_start_datatemplate (ipfix_exporter *exporter,
write_unsigned16 (&p_pos, p_end, template_id);
// write the field count:
write_unsigned16 (&p_pos, p_end, field_count);
if (datatemplate) {
// write the fixedfield count:
write_unsigned16 (&p_pos, p_end, fixedfield_count);
// write the preceding:
write_unsigned16 (&p_pos, p_end, preceding);
}
// ++ End of Template Record Header
exporter->template_arr[found_index].fields_length = (datatemplate ? 12 : 8);
exporter->template_arr[found_index].fields_length = 8;
return 0;
}
@ -2613,8 +2565,7 @@ int ipfix_put_template_field(ipfix_exporter *exporter, uint16_t template_id,
return -1;
}
if (exporter->template_arr[found_index].fields_added >=
exporter->template_arr[found_index].field_count +
exporter->template_arr[found_index].fixedfield_count) {
exporter->template_arr[found_index].field_count) {
msg(MSG_ERROR, "Cannot add more template fields.");
return -1;
}
@ -2656,124 +2607,6 @@ int ipfix_put_template_field(ipfix_exporter *exporter, uint16_t template_id,
return 0;
}
/*!
* \brief Start defining a new Template (Set).
*
* ipfixlolib supports only one Template Record per Template Set. So this
* function basically starts a Template Set and one Template Record.
*
* <em>Note:</em> It is not possible to start and define multiple Templates in parallel.
* ipfix_end_template() has to be called first before a new Template can be
* defined.
*
* Individual fields are added to the Template by calling
* ipfix_put_data_field() before calling ipfix_end_template() to end the
* Template.
*
* \param exporter pointer to previously initialized exporter struct
* \param template_id ID for this Template. Must be > 255.
* \param field_count number of fields that will be added to this Template Record.
* It is considered an error if more or fewer fields are added.
* \return 0 success
* \return -1 failure. Reasons might be that <tt>template_id</tt> is not great than 255
* or that the maximum number of defined templates has been exceeded.
* \sa ipfix_end_template(), ipfix_put_template_field(), ipfix_send()
**/
int ipfix_start_template (ipfix_exporter *exporter, uint16_t template_id, uint16_t field_count) {
return ipfix_start_datatemplate(exporter, template_id, 0, field_count, 0);
}
/*!
* \brief Append fixed-value data type field to the exporter's current Data
* Template Set, see <tt>ipfix_put_template_field()</tt>.
*
* \param exporter pointer to previously initialized exporter struct
* \param template_id ID of the template
* \param type Information Element ID of the field
* \param length length of the field (in host byte order)
* \param enterprise_id enterprise number (in host byte order) or 0 for Information Elements registered at IANA
* \return 0 success
* \return -1 failure
* \sa ipfix_start_datatemplate()
*/
int ipfix_put_template_fixedfield(ipfix_exporter *exporter, uint16_t template_id, uint16_t type, uint16_t length, uint32_t enterprise_id) {
if (exporter->export_protocol != IPFIX_PROTOCOL) {
msg(MSG_ERROR, "Only IPFIX supports data templates");
return -1;
}
return ipfix_put_template_field(exporter, template_id, type, length, enterprise_id);
}
/*!
* \brief Append fixed-value data to the exporter's current data template set
*
* \param exporter pointer to previously initialized exporter struct
* \param template_id ID of the template
* \param data pointer to the data (data must be in network byte order)
* \param data_length length of data to be added, in bytes
* \return 0 success
* \return -1 failure
* \sa ipfix_start_datatemplate()
*/
int ipfix_put_template_data(ipfix_exporter *exporter, uint16_t template_id, void* data, uint16_t data_length) {
int found_index;
/* set pointers to the buffer */
char *p_pos;
char *p_end;
int i;
if (exporter->export_protocol != IPFIX_PROTOCOL) {
msg(MSG_ERROR, "Only IPFIX supports data templates");
return -1;
}
found_index = ipfix_find_template(exporter, template_id);
/* test for a valid slot */
if (found_index < 0) {
msg(MSG_VDEBUG, "template ID %u not found", template_id);
return -1;
}
ipfix_lo_template *templ=(&(*exporter).template_arr[found_index]);
if (templ->fields_added != templ->field_count + templ->fixedfield_count) {
msg(MSG_ERROR, "All field specifiers must have been added before adding data values to Data Template Record.");
return -1;
}
templ->max_fields_length += data_length;
templ->template_fields=(char *)realloc(templ->template_fields, templ->max_fields_length);
/* beginning of the buffer */
p_pos = templ->template_fields;
// end of the buffer
p_end = p_pos + templ->max_fields_length;
#if 0
DPRINTFL(MSG_VDEBUG, "template found at %i", found_index);
DPRINTFL(MSG_VDEBUG, "A p_pos %p, p_end %p", p_pos, p_end);
DPRINTFL(MSG_VDEBUG, "max_fields_len %u ", (*exporter).template_arr[found_index].max_fields_length);
DPRINTFL(MSG_VDEBUG, "fieldss_len %u ", (*exporter).template_arr[found_index].fields_length);
#endif
// add offset to the buffer's beginning: this is, where we will write to.
p_pos += templ->fields_length;
#if 0
DPRINTFL(MSG_VDEBUG, "B p_pos %p, p_end %p", p_pos, p_end);
#endif
for(i = 0; i < data_length; i++) {
write_octet(&p_pos, p_end, *(((uint8_t*)data)+i) );
}
// add to the written length:
templ->fields_length += data_length;
return 0;
}
/*!
* \brief End a previously started and defined template, options template, or data template.
*
@ -2797,7 +2630,7 @@ int ipfix_end_template(ipfix_exporter *exporter, uint16_t template_id)
return -1;
}
ipfix_lo_template *templ=(&exporter->template_arr[found_index]);
if (templ->fields_added != templ->field_count + templ->fixedfield_count) {
if (templ->fields_added != templ->field_count) {
msg(MSG_ERROR, "Number of added template fields does not match number passed to ipfix_start_template");
ipfix_deinit_template(templ);
return -1;

View File

@ -314,7 +314,7 @@ typedef struct {
*/
/* Note that this ipfix_set_header struct is only used for data sets.
* The header of template sets is built up in a char array.
* (See ipfix_start_datatemplate)
* (See ipfix_start_template)
*/
typedef struct {
@ -548,13 +548,10 @@ typedef struct{
uint16_t template_id;
uint16_t field_count; // the number of fields the user announced
// when calling ipfix_start_template
uint16_t fixedfield_count;
// the number of fixed-value fields the
// user announced when calling ipfix_start_datatemplate
uint16_t fields_added; // make sure the user adds the exact the same number
// of fields he told us to add when calling
// ipfix_start_template()
// Make sure fields_added == field_count + fixedfield_count
// Make sure fields_added == field_count
// when the user calls ipfix_end_template()
int fields_length; // This also includes the length of the Set Header
// It's basically the number of bytes written
@ -628,9 +625,7 @@ int ipfix_add_collector(ipfix_exporter *exporter, const char *coll_ip_addr, uint
int ipfix_remove_collector(ipfix_exporter *exporter, const char *coll_ip_addr, uint16_t coll_port);
int ipfix_start_template(ipfix_exporter *exporter, uint16_t template_id, uint16_t field_count);
int ipfix_start_optionstemplate_set(ipfix_exporter *exporter, uint16_t template_id, uint16_t scope_length, uint16_t option_length);
int ipfix_start_datatemplate(ipfix_exporter *exporter, uint16_t template_id, uint16_t preceding, uint16_t field_count, uint16_t fixedfield_count);
int ipfix_put_template_field(ipfix_exporter *exporter, uint16_t template_id, uint16_t type, uint16_t length, uint32_t enterprise_id);
int ipfix_put_template_fixedfield(ipfix_exporter *exporter, uint16_t template_id, uint16_t type, uint16_t length, uint32_t enterprise_id);
int ipfix_end_template(ipfix_exporter *exporter, uint16_t template_id );
int ipfix_start_data_set(ipfix_exporter *exporter, uint16_t template_id);
uint16_t ipfix_get_remaining_space(ipfix_exporter *exporter);
@ -639,7 +634,6 @@ int ipfix_end_data_set(ipfix_exporter *exporter, uint16_t number_of_records);
int ipfix_cancel_data_set(ipfix_exporter *exporter);
int ipfix_set_data_field_marker(ipfix_exporter *exporter);
int ipfix_delete_data_fields_upto_marker(ipfix_exporter *exporter);
int ipfix_put_template_data(ipfix_exporter *exporter, uint16_t template_id, void* data, uint16_t data_length);
int ipfix_remove_template(ipfix_exporter *exporter, uint16_t template_id);
int ipfix_send(ipfix_exporter *exporter);
int ipfix_set_template_transmission_timer(ipfix_exporter *exporter, uint32_t timer);

View File

@ -97,8 +97,7 @@ void AutoFocus::onDataRecord(IpfixDataRecord* record)
{
// only treat non-Options Data Records (although we cannot be sure that there is a Flow inside)
if((record->templateInfo->setId != TemplateInfo::NetflowTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixDataTemplate)) {
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)) {
record->removeReference();
return;
}

View File

@ -59,8 +59,7 @@ void FrontPayloadSigMatcher::onDataRecord(IpfixDataRecord* record)
{
// only treat non-Options Data Records (although we cannot be sure that there is a Flow inside)
if((record->templateInfo->setId != TemplateInfo::NetflowTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixDataTemplate)) {
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)) {
record->removeReference();
return;
}

View File

@ -48,8 +48,7 @@ void HostStatistics::onDataRecord(IpfixDataRecord* record)
{
// only treat non-Options Data Records (although we cannot be sure that there is a Flow inside)
if((record->templateInfo->setId != TemplateInfo::NetflowTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixDataTemplate)) {
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)) {
record->removeReference();
return;
}

View File

@ -65,8 +65,7 @@ void P2PDetector::onDataRecord(IpfixDataRecord* record)
{
// only treat non-Options Data Records (although we cannot be sure that there is a Flow inside)
if((record->templateInfo->setId != TemplateInfo::NetflowTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixDataTemplate)) {
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)) {
record->removeReference();
return;
}

View File

@ -99,8 +99,7 @@ void RBSWormDetector::onDataRecord(IpfixDataRecord* record)
{
// only treat non-Options Data Records (although we cannot be sure that there is a Flow inside)
if((record->templateInfo->setId != TemplateInfo::NetflowTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixDataTemplate)) {
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)) {
record->removeReference();
return;
}

View File

@ -75,8 +75,7 @@ void TRWPortscanDetector::onDataRecord(IpfixDataRecord* record)
{
// only treat non-Options Data Records (although we cannot be sure that there is a Flow inside)
if((record->templateInfo->setId != TemplateInfo::NetflowTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixDataTemplate)) {
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)) {
record->removeReference();
return;
}

View File

@ -91,8 +91,7 @@ void FpaPacketGenerator::onDataRecord(IpfixDataRecord* record)
{
// only treat non-Options Data Records (although we cannot be sure that there is a Flow inside)
if((record->templateInfo->setId != TemplateInfo::NetflowTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixDataTemplate)) {
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)) {
record->removeReference();
return;
}

View File

@ -105,8 +105,7 @@ void FpaPcapExporter::onDataRecord(IpfixDataRecord* record)
{
// only treat non-Options Data Records (although we cannot be sure that there is a Flow inside)
if((record->templateInfo->setId != TemplateInfo::NetflowTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixDataTemplate)) {
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)) {
record->removeReference();
return;
}

View File

@ -98,8 +98,7 @@ uint64_t IpfixCsExporter::retrieveTime(IpfixDataRecord* record, InformationEleme
void IpfixCsExporter::onDataRecord(IpfixDataRecord* record)
{
if ((record->templateInfo->setId != TemplateInfo::NetflowTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixDataTemplate)) {
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)) {
record->removeReference();
return;
}

View File

@ -298,178 +298,6 @@ uint32_t IpfixParser::processOptionsTemplateSet(boost::shared_ptr<IpfixRecord::S
return numberOfRecords;
}
/**
* Processes an IPFIX DataTemplate set.
* Called by processMessage
* returns number of processed records
*/
uint32_t IpfixParser::processDataTemplateSet(boost::shared_ptr<IpfixRecord::SourceID> sourceId, boost::shared_array<uint8_t> message, IpfixSetHeader* set, uint8_t* endOfMessage) {
uint32_t numberOfRecords = 0;
uint8_t* endOfSet = (uint8_t*)set + ntohs(set->length);
uint8_t* record = (uint8_t*)&set->data;
/* check if set length lies within message boundaries */
if (endOfSet > endOfMessage) {
msg(MSG_ERROR, "IpfixParser: Data Template set exceeds message boundary!");
return 0;
}
/* Data template record are >= 4 byte, so we stop processing when fewer bytes are left */
while (record + 4 <= endOfSet) {
/* First cast to normal template header used for withdrawal message */
IpfixTemplateHeader* th = (IpfixTemplateHeader*)record;
record = (uint8_t*)&th->data;
if (th->fieldCount == 0) {
/* This is a Template withdrawal message */
templateBuffer->destroyBufferedTemplate(sourceId, ntohs(th->templateId));
numberOfRecords++;
continue;
}
IpfixDataTemplateHeader* dth = (IpfixDataTemplateHeader*)th;
record = (uint8_t*)&dth->data;
/* Non-withdrawal data template records are >= 8 byte */
if (record > endOfSet) {
msg(MSG_ERROR, "IpfixParser: Strange long padding in Data Template");
return numberOfRecords;
}
TemplateBuffer::BufferedTemplate* bt = new TemplateBuffer::BufferedTemplate;
boost::shared_ptr<TemplateInfo> ti(new TemplateInfo);
bt->sourceID = sourceId;
bt->recordLength = 0;
bt->templateInfo = ti;
ti->templateId = ntohs(dth->templateId);
ti->setId = TemplateInfo::IpfixDataTemplate;
ti->preceding = ntohs(dth->precedingRule);
ti->fieldCount = ntohs(dth->fieldCount);
ti->dataCount = ntohs(dth->dataCount);
ti->fieldInfo = (TemplateInfo::FieldInfo*)malloc(ti->fieldCount * sizeof(TemplateInfo::FieldInfo));
int isLengthVarying = 0;
uint16_t fieldNo;
for (fieldNo = 0; fieldNo < ti->fieldCount; fieldNo++) {
/* check if there are at least 4 bytes for this field */
if (record+4 > endOfSet) {
msg(MSG_ERROR, "IpfixParser: Data Template record exceeds set boundary!");
delete bt;
return numberOfRecords;
}
ti->fieldInfo[fieldNo].type.id = ntohs(*(uint16_t*)((uint8_t*)record+0));
ti->fieldInfo[fieldNo].type.length = ntohs(*(uint16_t*)((uint8_t*)record+2));
ti->fieldInfo[fieldNo].isVariableLength = (ti->fieldInfo[fieldNo].type.length == 65535);
ti->fieldInfo[fieldNo].offset = bt->recordLength;
bt->recordLength+=ti->fieldInfo[fieldNo].type.length;
if (ti->fieldInfo[fieldNo].type.length == 65535) {
isLengthVarying=1;
}
if (ti->fieldInfo[fieldNo].type.id & IPFIX_ENTERPRISE_TYPE) {
/* check if there are 8 bytes for this field */
if (record+8 > endOfSet) {
msg(MSG_ERROR, "IpfixParser: Data Template record exceeds set boundary!");
delete bt;
return numberOfRecords;
}
ti->fieldInfo[fieldNo].type.enterprise = ntohl(*(uint32_t*)((uint8_t*)record+4));
// remove highest bit
ti->fieldInfo[fieldNo].type.id &= ~IPFIX_ENTERPRISE_TYPE;
record = (uint8_t*)((uint8_t*)record+8);
} else {
ti->fieldInfo[fieldNo].type.enterprise = 0;
record = (uint8_t*)((uint8_t*)record+4);
}
}
if (isLengthVarying) {
bt->recordLength = 65535;
for (fieldNo = 0; fieldNo < ti->fieldCount; fieldNo++) {
ti->fieldInfo[fieldNo].offset = 0xFFFFFFFF;
}
}
ti->dataInfo = (TemplateInfo::FieldInfo*)malloc(ti->dataCount * sizeof(TemplateInfo::FieldInfo));
for (fieldNo = 0; fieldNo < ti->dataCount; fieldNo++) {
/* check if there are at least 4 bytes for this field */
if (record+4 > endOfSet) {
msg(MSG_ERROR, "IpfixParser: Data Template record exceeds set boundary!");
delete bt;
return numberOfRecords;
}
ti->dataInfo[fieldNo].type.id = ntohs(*(uint16_t*)((uint8_t*)record+0));
ti->dataInfo[fieldNo].type.length = ntohs(*(uint16_t*)((uint8_t*)record+2));
if (ti->dataInfo[fieldNo].type.id & IPFIX_ENTERPRISE_TYPE) {
/* check if there are 8 bytes for this field */
if (record+8 >= endOfSet) {
msg(MSG_ERROR, "IpfixParser: Data Template record exceeds set boundary!");
delete bt;
return numberOfRecords;
}
ti->dataInfo[fieldNo].type.enterprise = ntohl(*(uint32_t*)((uint8_t*)record+4));
// remove highest bit
ti->dataInfo[fieldNo].type.id &= ~IPFIX_ENTERPRISE_TYPE;
record = (uint8_t*)((uint8_t*)record+8);
} else {
ti->dataInfo[fieldNo].type.enterprise = 0;
record = (uint8_t*)((uint8_t*)record+4);
}
}
int dataLength = 0;
for (fieldNo = 0; fieldNo < ti->dataCount; fieldNo++) {
if (ti->dataInfo[fieldNo].type.length == 65535) {
/* check if there is 1 byte for the length */
if (record + dataLength + 1 > endOfSet) {
msg(MSG_ERROR, "IpfixParser: Template record exceeds set boundary!");
delete bt;
return numberOfRecords;
}
/* This is a variable-length field, get length from first byte and advance offset */
ti->dataInfo[fieldNo].type.length = *(uint8_t*)(record + dataLength);
dataLength += 1;
if (ti->dataInfo[fieldNo].type.length == 255) {
/* check if there are 2 bytes for the length */
if (record + dataLength + 2 > endOfSet) {
msg(MSG_ERROR, "IpfixParser: Template record exceeds set boundary!");
delete bt;
return numberOfRecords;
}
/* First byte did not suffice, length is stored in next two bytes. Advance offset */
ti->dataInfo[fieldNo].type.length = *(uint16_t*)(record + dataLength);
dataLength += 2;
}
}
ti->dataInfo[fieldNo].offset = dataLength;
dataLength += ti->dataInfo[fieldNo].type.length;
}
/* final check if entire fixed data block is within set boundary */
if (record + dataLength > endOfSet) {
msg(MSG_ERROR, "IpfixParser: Template record exceeds set boundary!");
delete bt;
return numberOfRecords;
}
/* Copy fixed data block */
ti->data = (IpfixRecord::Data*)malloc(dataLength*sizeof(IpfixRecord::Data));
ti->dataLength = dataLength;
memcpy(ti->data, record, dataLength*sizeof(IpfixRecord::Data));
/* Advance record to end of fixed data block, i.e. start of next template record */
record += dataLength;
templateBuffer->bufferTemplate(bt);
if((sourceId->protocol == IPFIX_protocolIdentifier_UDP) && (templateLifetime > 0))
bt->expires = time(0) + templateLifetime;
else
bt->expires = 0;
IpfixTemplateRecord* ipfixRecord = templateRecordIM.getNewInstance();
ipfixRecord->sourceID = sourceId;
ipfixRecord->templateInfo = ti;
push(ipfixRecord);
numberOfRecords++;
}
return numberOfRecords;
}
/**
* Processes an IPFIX data set.
* Called by processMessage
@ -501,9 +329,9 @@ uint32_t IpfixParser::processDataSet(boost::shared_ptr<IpfixRecord::SourceID> so
}
#ifdef SUPPORT_NETFLOWV9
if ((bt->templateInfo->setId == TemplateInfo::IpfixTemplate) || (bt->templateInfo->setId == TemplateInfo::IpfixOptionsTemplate) || (bt->templateInfo->setId == TemplateInfo::IpfixDataTemplate) || (bt->templateInfo->setId == TemplateInfo::NetflowTemplate) || (bt->templateInfo->setId == TemplateInfo::NetflowOptionsTemplate)) {
if ((bt->templateInfo->setId == TemplateInfo::IpfixTemplate) || (bt->templateInfo->setId == TemplateInfo::IpfixOptionsTemplate) || (bt->templateInfo->setId == TemplateInfo::NetflowTemplate) || (bt->templateInfo->setId == TemplateInfo::NetflowOptionsTemplate)) {
#else
if ((bt->templateInfo->setId == TemplateInfo::IpfixTemplate) || (bt->templateInfo->setId == TemplateInfo::IpfixOptionsTemplate) || (bt->templateInfo->setId == TemplateInfo::IpfixDataTemplate)) {
if ((bt->templateInfo->setId == TemplateInfo::IpfixTemplate) || (bt->templateInfo->setId == TemplateInfo::IpfixOptionsTemplate)) {
#endif
boost::shared_ptr<TemplateInfo> ti = bt->templateInfo;
@ -769,9 +597,6 @@ int IpfixParser::processIpfixPacket(boost::shared_array<uint8_t> message, uint16
tmpid=ntohs(set->id);
switch(tmpid) {
case IPFIX_SetId_DataTemplate:
numberOfTemplateRecords += processDataTemplateSet(sourceId, message, set, endOfMessage);
break;
case IPFIX_SetId_Template:
numberOfTemplateRecords += processTemplateSet(sourceId, TemplateInfo::IpfixTemplate, message, set, endOfMessage);
break;

View File

@ -115,18 +115,6 @@ class IpfixParser : public IpfixPacketProcessor, public Sensor
uint8_t data;
} IpfixTemplateHeader;
/**
* IPFIX "DataTemplate Set" helper.
* Constitutes the first bytes of every IPFIX DataTemplate
*/
typedef struct {
uint16_t templateId;
uint16_t fieldCount;
uint16_t dataCount;
uint16_t precedingRule;
uint8_t data;
} IpfixDataTemplateHeader;
/**
* IPFIX "Options Template Set" helper.
* Constitutes the first bytes of every IPFIX Options Template
@ -147,7 +135,6 @@ class IpfixParser : public IpfixPacketProcessor, public Sensor
uint32_t processDataSet(boost::shared_ptr<IpfixRecord::SourceID> sourceID, boost::shared_array<uint8_t> message, IpfixSetHeader* set, uint8_t* endOfMessage);
uint32_t processTemplateSet(boost::shared_ptr<IpfixRecord::SourceID> sourceID, TemplateInfo::SetId setId, boost::shared_array<uint8_t> message, IpfixSetHeader* set, uint8_t* endOfMessage);
uint32_t processDataTemplateSet(boost::shared_ptr<IpfixRecord::SourceID> sourceID, boost::shared_array<uint8_t> message, IpfixSetHeader* set, uint8_t* endOfMessage);
uint32_t processOptionsTemplateSet(boost::shared_ptr<IpfixRecord::SourceID> sourceId, TemplateInfo::SetId setId, boost::shared_array<uint8_t> message, IpfixSetHeader* set, uint8_t* endOfMessage);
int processNetflowV9Packet(boost::shared_array<uint8_t> message, uint16_t length, boost::shared_ptr<IpfixRecord::SourceID> sourceId);
int processIpfixPacket(boost::shared_array<uint8_t> message, uint16_t length, boost::shared_ptr<IpfixRecord::SourceID> sourceId);

View File

@ -65,8 +65,7 @@ void IpfixPayloadWriter::onDataRecord(IpfixDataRecord* record)
{
// only treat non-Options Data Records (although we cannot be sure that there is a Flow inside)
if((record->templateInfo->setId != TemplateInfo::NetflowTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixDataTemplate)) {
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)) {
record->removeReference();
return;
}

View File

@ -394,9 +394,6 @@ void IpfixPrinter::onTemplate(IpfixTemplateRecord* record)
case TemplateInfo::IpfixOptionsTemplate:
fprintf(fh, "\n-+--- Ipfix Options Template (id=%u, uniqueId=%u) from ", templateInfo->templateId, templateInfo->getUniqueId());
break;
case TemplateInfo::IpfixDataTemplate:
fprintf(fh, "\n-+--- Ipfix Data Template (id=%u, preceding=%u, uniqueId=%u) from ", templateInfo->templateId, templateInfo->preceding, templateInfo->getUniqueId());
break;
default:
msg(MSG_ERROR, "IpfixPrinter: Template with unknown setId=%u, uniqueId=%u", templateInfo->setId, templateInfo->getUniqueId());
@ -422,16 +419,6 @@ void IpfixPrinter::onTemplate(IpfixTemplateRecord* record)
}
}
// print fixed data in the case of a data template
if(templateInfo->setId == TemplateInfo::IpfixDataTemplate) {
fprintf(fh, " `- fixed data\n");
for (int i = 0; i < templateInfo->dataCount; i++) {
fprintf(fh, " ' `- ");
printFieldData(templateInfo->dataInfo[i].type,
(templateInfo->data + templateInfo->dataInfo[i].offset));
fprintf(fh, "\n");
}
}
fprintf(fh, " `---\n\n");
break;
@ -463,9 +450,6 @@ void IpfixPrinter::onTemplateDestruction(IpfixTemplateDestructionRecord* record)
case TemplateInfo::IpfixOptionsTemplate:
fprintf(fh, "\n-+--- Destroyed Ipfix Options Template (id=%u, uniqueId=%u) from ", templateInfo->templateId, templateInfo->getUniqueId());
break;
case TemplateInfo::IpfixDataTemplate:
fprintf(fh, "\n-+--- Destroyed Ipfix Data Template (id=%u, uniqueId=%u) from ", templateInfo->templateId, templateInfo->getUniqueId());
break;
default:
msg(MSG_ERROR, "IpfixPrinter: Template destruction recordwith unknown setId=%u, uniqueId=%u", templateInfo->setId, templateInfo->getUniqueId());
@ -657,9 +641,6 @@ void IpfixPrinter::printTreeRecord(IpfixDataRecord* record)
case TemplateInfo::IpfixOptionsTemplate:
fprintf(fh, "\n-+--- Ipfix Options Data Record (id=%u) from ", record->templateInfo->templateId);
break;
case TemplateInfo::IpfixDataTemplate:
fprintf(fh, "\n-+--- Ipfix Data Data Record (id=%u, preceding=%u) from ", record->templateInfo->templateId, record->templateInfo->preceding);
break;
default:
msg(MSG_ERROR, "IpfixPrinter: Template with unknown setid=%u", record->templateInfo->setId);
@ -676,16 +657,6 @@ void IpfixPrinter::printTreeRecord(IpfixDataRecord* record)
fprintf(fh, "no sourceID given");
}
if(record->templateInfo->setId == TemplateInfo::IpfixDataTemplate) {
fprintf(fh, " `- fixed data\n");
for (i = 0; i < record->templateInfo->dataCount; i++) {
fprintf(fh, " ' `- ");
printFieldData(record->templateInfo->dataInfo[i].type,
(record->templateInfo->data + record->templateInfo->dataInfo[i].offset));
fprintf(fh, "\n");
}
}
if(record->templateInfo->setId == TemplateInfo::IpfixOptionsTemplate) {
fprintf(fh, " `- variable scope data\n");
for(i = 0; i < record->templateInfo->scopeCount; i++) {

View File

@ -208,7 +208,7 @@ namespace InformationElement {
TemplateInfo::TemplateInfo() : templateId(0), setId(UnknownSetId), fieldCount(0), fieldInfo(NULL),
freePointers(true),
scopeCount(0), scopeInfo(NULL), dataCount(0), dataInfo(NULL), preceding(0), dataLength(0), data(NULL),
scopeCount(0), scopeInfo(NULL),
uniqueId(0)
{
setUniqueId();
@ -231,15 +231,6 @@ TemplateInfo::TemplateInfo(const TemplateInfo& t)
scopeInfo = (FieldInfo*)malloc(scopeCount*sizeof(FieldInfo));
memcpy(scopeInfo, t.scopeInfo, scopeCount*sizeof(FieldInfo));
// copy Data Template data fields and further attributes
dataCount = t.dataCount;
dataInfo = (FieldInfo*)malloc(dataCount*sizeof(FieldInfo));
memcpy(dataInfo, t.dataInfo, dataCount*sizeof(FieldInfo));
preceding = t.preceding;
dataLength = t.dataLength;
data = (IpfixRecord::Data*)malloc(dataLength*sizeof(IpfixRecord::Data));
memcpy(data, t.data, dataLength*sizeof(IpfixRecord::Data));
// copy uniqueId (a new uniqueId can be assigned with setUniqueId() if needed)
uniqueId = t.uniqueId;
// increase reference count in uniqueIdUseCount()
@ -257,8 +248,6 @@ TemplateInfo::~TemplateInfo() {
{
free(fieldInfo);
free(scopeInfo);
free(dataInfo);
free(data);
freePointers = false;
}
// decrease reference count in uniqueIdUseCount()
@ -355,31 +344,3 @@ int TemplateInfo::getFieldIndex(InformationElement::IeId fieldTypeId, Informatio
return -1;
}
/**
* Gets data of Data Templates for a given Information Element.
* @param type Information Element to get data for
* @return NULL if not found
*/
TemplateInfo::FieldInfo* TemplateInfo::getDataInfo(const InformationElement::IeInfo& type) {
return getDataInfo(type.id, type.enterprise);
}
/**
* Gets data of Data Templates for a given Information Element Id and enterprise number.
* @param fieldTypeId Information Element id to look for
* @param fieldTypeEid enterprise number to look for
* @return NULL if not found
*/
TemplateInfo::FieldInfo* TemplateInfo::getDataInfo(InformationElement::IeId fieldTypeId, InformationElement::IeEnterpriseNumber fieldTypeEid) {
int i;
for (i = 0; i < dataCount; i++) {
if ((dataInfo[i].type.id == fieldTypeId) && (dataInfo[i].type.enterprise == fieldTypeEid)) {
return &dataInfo[i];
}
}
return NULL;
}

View File

@ -231,7 +231,6 @@ class TemplateInfo {
NetflowOptionsTemplate = 1,
IpfixTemplate = 2,
IpfixOptionsTemplate = 3,
IpfixDataTemplate = 4
};
/**
@ -257,8 +256,6 @@ class TemplateInfo {
FieldInfo* getFieldInfo(InformationElement::IeId fieldTypeId, InformationElement::IeEnterpriseNumber fieldTypeEid);
int getFieldIndex(const InformationElement::IeInfo& type);
int getFieldIndex(InformationElement::IeId fieldTypeId, InformationElement::IeEnterpriseNumber fieldTypeEid);
FieldInfo* getDataInfo(const InformationElement::IeInfo& type);
FieldInfo* getDataInfo(InformationElement::IeId fieldTypeId, InformationElement::IeEnterpriseNumber fieldTypeEid);
TemplateId templateId; /**< the template id assigned to this template */
SetId setId; /**< set Id */
@ -271,13 +268,6 @@ class TemplateInfo {
uint16_t scopeCount; /**< number of scope fields */
FieldInfo* scopeInfo; /**< array of FieldInfos describing each of these fields */
// only used by Data Templates:
uint16_t dataCount; /**< number of fixed-value fields */
FieldInfo* dataInfo; /**< array of FieldInfos describing each of these fields */
uint16_t preceding; /**< the preceding rule field as defined in the draft */
uint16_t dataLength;
IpfixRecord::Data* data; /**< data start pointer for fixed-value fields */
private:
/* uniqueId:
* - uniqueId>0 is a Vermont-wide unique identifier for a Template

View File

@ -29,16 +29,6 @@ void IpfixRecordAnonymizer::setCopyMode(bool mode)
void IpfixRecordAnonymizer::onTemplate(IpfixTemplateRecord* record)
{
//TODO: anonymize Data Templates
if((record->templateInfo->setId == TemplateInfo::IpfixDataTemplate) && (record->templateInfo->dataCount != 0)) {
for (int i = 0; i != record->templateInfo->dataCount; ++i) {
TemplateInfo::FieldInfo* field = record->templateInfo->dataInfo + i;
// check if this fixed value field should be anonymized
if (methods.find(field->type) != methods.end())
msg(MSG_ERROR, "IpfixRecordAnonymizer: Anonymization not supported for fixed value field (ie=%u, enterprise=%u) in Data Template (id=%u)", field->type.id, field->type.enterprise, record->templateInfo->templateId);
}
}
send(record);
}
@ -59,25 +49,6 @@ void IpfixRecordAnonymizer::onDataRecord(IpfixDataRecord* record)
} else
myRecord = record;
/* TODO (Gerhard 12/2009): Anonymization of Data Template does not make sense if implemented at this place (only).
* For example, the IpfixSender uses the Templates received by onTemplate(...), not the ones linked to the
* Data Records. Therefore, anonymization should take place in IpfixRecordAnonymizer::onTemplate().
* The anonymized Data Template should then be linked to all the corresponding Data Records.
*
// anonymize data template fixed value fields if necessary
if((myRecord->templateInfo->setId==TemplateInfo::IpfixDataRecord) && (!myRecord->templateInfo->anonymized)) {
// copy Data Template Info in copy mode
if(copyMode)
myRecord->templateInfo = boost::shared_ptr<TemplateInfo>(new TemplateInfo(*record->templateInfo.get()));
for (int i = 0; i != myRecord->templateInfo->dataCount; ++i) {
TemplateInfo::FieldInfo* field = myRecord->templateInfo->dataInfo + i;
anonField(field->type.id, myRecord->templateInfo->data + field->offset, field->type.length);
}
myRecord->templateInfo->anonymized = true;
}
*/
boost::shared_ptr<TemplateInfo> templateInfo = myRecord->templateInfo;
// anonymize Data Record fields

View File

@ -253,7 +253,7 @@ void IpfixSender::onTemplate(IpfixTemplateRecord* record)
{
boost::shared_ptr<TemplateInfo> dataTemplateInfo = record->templateInfo;
// TODO: Implement Options Template handling
if ((dataTemplateInfo->setId != TemplateInfo::IpfixTemplate) && (dataTemplateInfo->setId != TemplateInfo::IpfixDataTemplate))
if ((dataTemplateInfo->setId != TemplateInfo::IpfixTemplate))
{
msg(MSG_ERROR, "IpfixSender: Don't know how to handle Template (setId=%u)", dataTemplateInfo->setId);
record->removeReference();
@ -309,16 +309,6 @@ void IpfixSender::onTemplate(IpfixTemplateRecord* record)
//for(map<TemplateInfo::TemplateId, uint16_t>::iterator iter = templateIdToUniqueId.begin(); iter != templateIdToUniqueId.end(); iter++) msg(MSG_FATAL, "template id %u -> unique id %u", iter->first, iter->second);
//for(map<uint16_t, TemplateInfo::TemplateId>::iterator iter = uniqueIdToTemplateId.begin(); iter != uniqueIdToTemplateId.end(); iter++) msg(MSG_FATAL, "unique id %u -> template id %u", iter->first, iter->second);
uint16_t my_preceding = 0;
// Translate preceding template id if possible
if(dataTemplateInfo->preceding) {
map<TemplateInfo::TemplateId, uint16_t>::iterator iter = templateIdToUniqueId.find(dataTemplateInfo->preceding);
if(iter == templateIdToUniqueId.end())
msg(MSG_ERROR, "IpfixSender: Preceding Template (id=%u) not available, use zero instead", dataTemplateInfo->preceding);
else
my_preceding = uniqueIdToTemplateId[iter->second];
}
int i;
/* Count number of IPv4 fields with length 5 */
@ -333,20 +323,8 @@ void IpfixSender::onTemplate(IpfixTemplateRecord* record)
}
}
/* Count number of IPv4 fields with length 5 */
int splitFixedfields = 0;
for (i = 0; i < dataTemplateInfo->dataCount; i++) {
TemplateInfo::FieldInfo* fi = &dataTemplateInfo->dataInfo[i];
if ((fi->type.id == IPFIX_TYPEID_sourceIPv4Address) && (fi->type.length == 5)) {
splitFixedfields++;
}
else if ((fi->type.id == IPFIX_TYPEID_destinationIPv4Address) && (fi->type.length == 5)) {
splitFixedfields++;
}
}
if (0 != ipfix_start_datatemplate(ipfixExporter, my_template_id, my_preceding, dataTemplateInfo->fieldCount + splitFields, dataTemplateInfo->dataCount + splitFixedfields)) {
THROWEXCEPTION("IpfixSender: ipfix_start_datatemplate failed");
if (0 != ipfix_start_template(ipfixExporter, my_template_id, dataTemplateInfo->fieldCount + splitFields)) {
THROWEXCEPTION("IpfixSender: ipfix_start_template failed");
}
for (i = 0; i < dataTemplateInfo->fieldCount; i++) {
@ -371,67 +349,6 @@ void IpfixSender::onTemplate(IpfixTemplateRecord* record)
}
}
DPRINTF("%u data fields", dataTemplateInfo->dataCount);
int dataLength = 0;
for (i = 0; i < dataTemplateInfo->dataCount; i++) {
TemplateInfo::FieldInfo* fi = &dataTemplateInfo->dataInfo[i];
dataLength += fi->type.length;
/* Split IPv4 fields with length 5, i.e. fields with network mask attached */
if ((fi->type.id == IPFIX_TYPEID_sourceIPv4Address) && (fi->type.length == 5)) {
ipfix_put_template_fixedfield(ipfixExporter, my_template_id, IPFIX_TYPEID_sourceIPv4Address, 4, 0);
ipfix_put_template_fixedfield(ipfixExporter, my_template_id, IPFIX_TYPEID_sourceIPv4PrefixLength, 1, 0);
}
else if ((fi->type.id == IPFIX_TYPEID_destinationIPv4Address) && (fi->type.length == 5)) {
ipfix_put_template_fixedfield(ipfixExporter, my_template_id, IPFIX_TYPEID_destinationIPv4Address, 4, 0);
ipfix_put_template_fixedfield(ipfixExporter, my_template_id, IPFIX_TYPEID_destinationIPv4PrefixLength, 1, 0);
}
else if ((export_protocol == NFV9_PROTOCOL) &&
(fi->type.id == IPFIX_TYPEID_tcpControlBits) &&
(fi->type.length != 1)) {
ipfix_put_template_fixedfield(ipfixExporter, my_template_id, IPFIX_TYPEID_tcpControlBits, 1, 0);
}
else {
ipfix_put_template_fixedfield(ipfixExporter, my_template_id, fi->type.id, fi->type.length, fi->type.enterprise);
}
}
DPRINTF("%u data length", dataLength);
char *data = NULL; // electric fence does not like 0-byte mallocs
if (dataLength && dataTemplateInfo->dataCount) {
data = (char *)malloc(dataLength);
if (!data) {
THROWEXCEPTION("IpfixSender: could not allocate data template");
}
memcpy(data, dataTemplateInfo->data, dataLength);
}
for (i = 0; i < dataTemplateInfo->dataCount; i++) {
TemplateInfo::FieldInfo* fi = &dataTemplateInfo->dataInfo[i];
/* Invert imask of IPv4 fields with length 5, i.e. fields with network mask attached */
if ((fi->type.id == IPFIX_TYPEID_sourceIPv4Address) && (fi->type.length == 5)) {
uint8_t* mask = (uint8_t*)(data + fi->offset + 4);
*mask = 32 - *mask;
}
else if ((fi->type.id == IPFIX_TYPEID_destinationIPv4Address) && (fi->type.length == 5)) {
uint8_t* mask = (uint8_t*)(data + fi->offset + 4);
*mask = 32 - *mask;
}
else {
}
}
// Only add Data Template data if there is any
if (data && ipfix_put_template_data(ipfixExporter, my_template_id, data, dataLength)) {
THROWEXCEPTION("IpfixSender: ipfix_put_template_data failed");
}
free(data);
if (0 != ipfix_end_template(ipfixExporter, my_template_id)) {
THROWEXCEPTION("IpfixSender: ipfix_end_template failed");
}
@ -459,7 +376,7 @@ void IpfixSender::onTemplateDestruction(IpfixTemplateDestructionRecord* record)
{
boost::shared_ptr<TemplateInfo> dataTemplateInfo = record->templateInfo;
// TODO: Implement Options Template handling
if ((dataTemplateInfo->setId != TemplateInfo::IpfixTemplate) && (dataTemplateInfo->setId != TemplateInfo::IpfixDataTemplate))
if ((dataTemplateInfo->setId != TemplateInfo::IpfixTemplate))
{
msg(MSG_ERROR, "IpfixSender: Don't know how to handle Template (setId=%u)", dataTemplateInfo->setId);
record->removeReference();
@ -615,7 +532,7 @@ void IpfixSender::onDataRecord(IpfixDataRecord* record)
{
boost::shared_ptr<TemplateInfo> dataTemplateInfo = record->templateInfo;
// TODO: Implement Options Data Record handling
if ((dataTemplateInfo->setId != TemplateInfo::IpfixTemplate) && (dataTemplateInfo->setId != TemplateInfo::IpfixDataTemplate))
if ((dataTemplateInfo->setId != TemplateInfo::IpfixTemplate))
{
msg(MSG_ERROR, "IpfixSender: Don't know how to handle Template (setId=%u)", dataTemplateInfo->setId);
record->removeReference();

View File

@ -74,8 +74,6 @@ Rule* AggregatorBaseCfg::readRule(XMLElement* elem) {
if (e->matches("templateId")) {
rule->id = getInt("templateId", 0, e);
} else if (e->matches("preceding")) {
rule->preceding = getInt("preceding", 0, e);
} else if (e->matches("biflowAggregation")) {
rule->biflowAggregation = getInt("biflowAggregation", 0, e);
} else if (e->matches("flowKey")) {

View File

@ -117,24 +117,6 @@ void BaseAggregator::postReconfiguration()
}
}
/**
* initializes aggregator module and creates hashtable
* @param rulefile filename with rules to import
* @param inactiveTimeout minimum buffer time for flows in hashtable
* @param activeTimeout maximum buffer time for flows in hashtable
*/
void BaseAggregator::buildAggregator(char* rulefile, uint16_t inactiveTimeout, uint16_t activeTimeout, uint8_t hashbits)
{
Rules* rules = new Rules(rulefile);
if (!rules) {
THROWEXCEPTION("could not parse rules file %s", rulefile);
}
buildAggregator(rules, inactiveTimeout, activeTimeout, hashbits);
}
/**
* initializes aggregator module and creates hashtable
* @param rules rules to use for creation of hashtables

View File

@ -36,7 +36,6 @@ public:
virtual ~BaseAggregator();
void buildAggregator(Rules* rules, uint16_t inactiveTimeout, uint16_t activeTimeout, uint8_t hashbits);
void buildAggregator(char* rulefile, uint16_t inactiveTimeout, uint16_t activeTimeout, uint8_t hashbits);
// events from Module
virtual void preReconfiguration();

View File

@ -100,17 +100,11 @@ uint32_t BaseHashtable::getPrivateDataLength(const InformationElement::IeInfo& t
void BaseHashtable::createDataTemplate(Rule* rule)
{
int dataLength = 0; /**< length in bytes of the @c data field */
dataTemplate.reset(new TemplateInfo);
dataTemplate->templateId = rule->id;
// Let's first assume that this is a normal Template
if(rule->preceding != 0) {
dataTemplate->preceding = rule->preceding;
dataTemplate->setId = TemplateInfo::IpfixDataTemplate;
} else {
dataTemplate->setId = TemplateInfo::IpfixTemplate;
}
dataTemplate->setId = TemplateInfo::IpfixTemplate;
fieldLength = 0;
fieldModifier = (Rule::Field::Modifier*) malloc(rule->fieldCount
@ -119,32 +113,7 @@ void BaseHashtable::createDataTemplate(Rule* rule)
for (int32_t i = 0; i < rule->fieldCount; i++) {
Rule::Field* rf = rule->field[i];
if (rf->pattern != NULL) {
// This is a Data Template
dataTemplate->setId = TemplateInfo::IpfixDataTemplate;
/* create new fixed-data field containing pattern */
dataTemplate->dataCount++;
dataTemplate->dataInfo = (TemplateInfo::FieldInfo*) realloc(dataTemplate->dataInfo,
sizeof(TemplateInfo::FieldInfo) * dataTemplate->dataCount);
TemplateInfo::FieldInfo* fi = &dataTemplate->dataInfo[dataTemplate->dataCount - 1];
fi->type = rf->type;
fi->offset = dataLength;
fi->privDataOffset = 0;
dataLength += fi->type.length;
dataTemplate->dataLength = dataLength;
dataTemplate->data = (IpfixRecord::Data*)realloc(dataTemplate->data, dataLength);
memcpy(dataTemplate->data + fi->offset, rf->pattern, fi->type.length);
}
/* gerhard: If we have a pattern (and fixed value field), the variable value field is implicitely discarded.
* Note: This is necessary because of the double meaning/usage of Rule::Field.type.length:
* If a pattern is present, this variable holds the length of the pattern (or fixed length field)
* and not the length of the normal field holding a single value. As a consequence, we cannot use
* Rule.Field.type.length as length of the variable value field.
* If someone really wants to enable the export of both, pattern and variable value field of the same
* type, then he has to remove the double meaning/usage (or set the variable field length to the
* default value for the specific type).
*/
else if (rf->modifier != Rule::Field::DISCARD) {
if (rf->modifier != Rule::Field::DISCARD) {
/* define new data field with Rule::Field's type */
dataTemplate->fieldCount++;
dataTemplate->fieldInfo = (TemplateInfo::FieldInfo*) realloc(dataTemplate->fieldInfo,

View File

@ -740,54 +740,6 @@ void FlowHashtable::aggregateDataRecord(IpfixDataRecord* record)
continue;
}
// If this is a Data Record, search in fixed value fields
if((ti->setId==TemplateInfo::IpfixDataTemplate) && (ti->dataCount > 0)) {
/* No matching variable field. Copy from matching fixed field, should it exist */
tfi = ti->getDataInfo(hfi->type);
if (tfi) {
fieldFilled = true;
copyData(hfi, htdata.get(), tfi, ti->data, fieldModifier[i]);
/* copy associated mask, should there be one */
switch (hfi->type.id) {
case IPFIX_TYPEID_sourceIPv4Address:
tfi = ti->getDataInfo(IPFIX_TYPEID_sourceIPv4PrefixLength, 0);
if(tfi) {
if(hfi->type.length != 5) {
DPRINTF("Tried to set mask of length %d IP address\n", hfi->type.length);
} else {
if(tfi->type.length == 1) {
*(uint8_t*)(htdata.get() + hfi->offset + 4) = *(uint8_t*)(ti->data + tfi->offset);
} else {
DPRINTF("Cannot process associated mask with invalid length %d\n", tfi->type.length);
}
}
}
break;
case IPFIX_TYPEID_destinationIPv4Address:
tfi = ti->getDataInfo(IPFIX_TYPEID_destinationIPv4PrefixLength, 0);
if(tfi) {
if(hfi->type.length != 5) {
DPRINTF("Tried to set mask of length %d IP address\n", hfi->type.length);
} else {
if (tfi->type.length == 1) {
*(uint8_t*)(htdata.get() + hfi->offset + 4) = *(uint8_t*)(ti->data + tfi->offset);
} else {
DPRINTF("Cannot process associated mask with invalid length %d\n", tfi->type.length);
}
}
}
break;
default:
break;
}
continue;
}
}
if (!fieldFilled) {
DPRINTF("Flow to be buffered did not contain %s field\n", hfi->type.toString().c_str());
// if field was not copied, fill it with 0

View File

@ -64,8 +64,7 @@ void IpfixAggregator::onDataRecord(IpfixDataRecord* record)
// only treat non-Options Data Records (although we cannot be sure that there is a Flow inside)
if((record->templateInfo->setId != TemplateInfo::NetflowTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)
&& (record->templateInfo->setId != TemplateInfo::IpfixDataTemplate)) {
&& (record->templateInfo->setId != TemplateInfo::IpfixTemplate)) {
record->removeReference();
return;
}

View File

@ -41,7 +41,7 @@
/* --- functions ------------*/
Rule::Rule()
: id(0), preceding(0), fieldCount(0), biflowAggregation(0), hashtable(0), patternFields(0), patternFieldsLen(0)
: id(0), fieldCount(0), biflowAggregation(0), hashtable(0), patternFields(0), patternFieldsLen(0)
{
}
@ -108,7 +108,7 @@ const char* modifier2string(Rule::Field::Modifier i) {
void Rule::print() {
int i;
printf("Aggregate %d %d\n",id,preceding);
printf("Aggregate %d\n",id);
for (i=0; i < fieldCount; i++) {
printf("\t");
const char* modifier = modifier2string(field[i]->modifier);
@ -434,45 +434,6 @@ int Rule::dataRecordMatches(IpfixDataRecord* record) {
}
*/
/*
in the case of Data Template, see if we find a corresponding fixed data field
*/
if ((dataTemplateInfo->setId == TemplateInfo::IpfixDataTemplate) && (dataTemplateInfo->dataCount > 0)) {
recordField = dataTemplateInfo->getDataInfo(ruleField->type);
if (recordField) {
/* corresponding fixed data field found, check if it matches. If it doesn't the whole rule cannot be matched */
if (!matchesPattern(&recordField->type, (dataTemplateInfo->data + recordField->offset), &ruleField->type, ruleField->pattern)) return 0;
if ((ruleField->type.enterprise == 0) && (ruleField->type.length == 5)) {
if (ruleField->type.id == IPFIX_TYPEID_sourceIPv4Address) {
if(!checkMask(dataTemplateInfo->getDataInfo(IPFIX_TYPEID_sourceIPv4PrefixLength, 0), dataTemplateInfo->data, ruleField)) return 0;
} else if (ruleField->type.id == IPFIX_TYPEID_destinationIPv4Address) {
if(!checkMask(dataTemplateInfo->getDataInfo(IPFIX_TYPEID_destinationIPv4PrefixLength, 0), dataTemplateInfo->data, ruleField)) return 0;
}
}
continue;
}
/* Probably, this does not lead to the desired result:
if (biflowAggregation) {
// check if the rule field as a corresponding type in opposite direction
InformationElement::IeId oppDirIeId = InformationElement::oppositeDirectionIeId(ruleField->type);
if(oppDirIeId) {
recordField = dataTemplateInfo->getDataInfo(oppDirIeId, ruleField->type.enterprise);
if (recordField) {
// corresponding data field found, check if it matches. If it doesn't the whole rule cannot be matched
if (!matchesPattern(&recordField->type, (dataTemplateInfo->data + recordField->offset), &ruleField->type, ruleField->pattern)) return 0;
if ((ruleField->type.enterprise == 0) && (ruleField->type.length == 5)) {
if (oppDirIeId == IPFIX_TYPEID_sourceIPv4Address) {
if(!checkMask(dataTemplateInfo->getDataInfo(IPFIX_TYPEID_sourceIPv4PrefixLength, 0), dataTemplateInfo->data, ruleField)) return 0;
} else if (oppDirIeId == IPFIX_TYPEID_destinationIPv4Address) {
if(!checkMask(dataTemplateInfo->getDataInfo(IPFIX_TYPEID_destinationIPv4PrefixLength, 0), dataTemplateInfo->data, ruleField)) return 0;
}
}
continue;
}
}
} */
}
/* no corresponding data field or fixed data field found, this flow cannot match */
msg(MSG_VDEBUG, "No corresponding DataDataRecord field for RuleField of type %s", ruleField->type.toString().c_str());
return 0;
@ -489,21 +450,6 @@ int Rule::dataRecordMatches(IpfixDataRecord* record) {
if (recordField) continue;
}
/*
in the case of Data Template, see if we find a corresponding fixed data field
*/
if ((dataTemplateInfo->setId == TemplateInfo::IpfixDataTemplate) && (dataTemplateInfo->dataCount > 0)) {
recordField = dataTemplateInfo->getDataInfo(ruleField->type);
if (recordField) continue;
/* in the case of biflow, we also check the reverse direction */
if (biflowAggregation && ruleField->type.existsReverseDirection()) {
InformationElement::IeInfo revie = ruleField->type.getReverseDirection();
recordField = dataTemplateInfo->getDataInfo(revie);
if (recordField) continue;
}
}
// anonymisationType is filled by the anonymizer, so we ignore it quietly
if (ruleField->type==InformationElement::IeInfo(IPFIX_ETYPEID_anonymisationType, IPFIX_PEN_vermont))
continue;
@ -519,7 +465,6 @@ int Rule::dataRecordMatches(IpfixDataRecord* record) {
bool operator==(const Rule &rhs, const Rule &lhs) {
if (rhs.id != lhs.id) return false;
if (rhs.preceding != lhs.preceding) return false;
if (rhs.fieldCount != lhs.fieldCount) return false;
if (rhs.biflowAggregation != lhs.biflowAggregation) return false;
if (rhs.patternFieldsLen != lhs.patternFieldsLen) return false;

View File

@ -79,7 +79,6 @@ class Rule : private PrintHelpers {
friend bool operator!=(const Rule &rhs, const Rule &lhs);
uint16_t id;
uint16_t preceding;
int fieldCount;
uint32_t biflowAggregation; /**< true if biflows have to be aggregated */
Rule::Field* field[MAX_RULE_FIELDS];

View File

@ -245,139 +245,6 @@ Rules::~Rules() {
Rules::Rules() : count(0) {
}
/**
* Reads in a ruleset from the specified file
*/
Rules::Rules(char* fname) {
FILE* f;
char buf[MAX_LINE_LEN];
char* p;
int lineNo = 0;
int block = 0;
count = 0;
Rule* currentRule = new Rule();
Rule::Field* ruleField = new Rule::Field();
f = fopen(fname, "r");
assert(f);
while (fgets(buf, sizeof(buf), f)) {
lineNo++;
if (strlen(buf) < 3) continue;
if (*buf == '#') continue;
p = buf;
char* col1 = get_next_token(&p, " \t\n");
char* modifier = get_next_token(&p, " \t\n");
char* field = get_next_token(&p, " \t\n");
get_next_token(&p, " \t\n");
char* pattern = get_next_token(&p, " \t\n");
if (col1 && *col1 != 0) {
if(strcmp(col1,"Aggregate")) {
msg(MSG_ERROR, "Unparsable block %s, o.%d", fname, lineNo);
block = 0;
continue;
}
/* Start of new Rule */
block=1;
if (currentRule->fieldCount > 0) {
rule[count++] = currentRule;
currentRule = new Rule();
}
currentRule->id=modifier?atoi(modifier):0;
currentRule->preceding=field?atoi(field):0;
continue;
}
if (!col1 || !block) {
msg(MSG_ERROR, "Unparseable line in %s, l.%d", fname, lineNo);
continue;
}
if (!field) {
msg(MSG_ERROR, "Incomplete line in %s, l.%d", fname, lineNo);
continue;
}
if (parseModifier(modifier, &ruleField->modifier) != 0) {
msg(MSG_ERROR, "Bad modifier \"%s\" in %s, l.%d", modifier, fname, lineNo);
continue;
}
const ipfix_identifier* ipfixid = ipfix_name_lookup(field);
if (!ipfixid) {
msg(MSG_ERROR, "Bad field type \"%s\" in %s, l.%d", field, fname, lineNo);
continue;
}
ruleField->type = InformationElement::IeInfo(ipfixid->id, ipfixid->pen);
if (ruleField->type.length == 0) {
msg(MSG_ERROR, "Bad field type \"%s\" in %s, l.%d", field, fname, lineNo);
continue;
}
if ((ruleField->type.id == IPFIX_TYPEID_sourceIPv4Address) || (ruleField->type.id == IPFIX_TYPEID_destinationIPv4Address)) {
ruleField->type.length++; // for additional mask field
}
ruleField->pattern = NULL;
if (pattern)
switch (ruleField->type.id) {
case IPFIX_TYPEID_protocolIdentifier:
if (parseProtoPattern(pattern, &ruleField->pattern, &ruleField->type.length) != 0) {
msg(MSG_ERROR, "Bad protocol pattern \"%s\" in %s, l.%d", pattern, fname, lineNo);
continue;
}
break;
case IPFIX_TYPEID_sourceIPv4Address:
case IPFIX_TYPEID_destinationIPv4Address:
if (parseIPv4Pattern(pattern, &ruleField->pattern, &ruleField->type.length) != 0) {
msg(MSG_ERROR, "Bad IPv4 pattern \"%s\" in %s, l.%d", pattern, fname, lineNo);
continue;
}
break;
case IPFIX_TYPEID_sourceTransportPort:
case IPFIX_TYPEID_udpSourcePort:
case IPFIX_TYPEID_tcpSourcePort:
case IPFIX_TYPEID_destinationTransportPort:
case IPFIX_TYPEID_udpDestinationPort:
case IPFIX_TYPEID_tcpDestinationPort:
if (parsePortPattern(pattern, &ruleField->pattern, &ruleField->type.length) != 0) {
msg(MSG_ERROR, "Bad PortRanges pattern \"%s\" in %s, l.%d", pattern, fname, lineNo);
continue;
}
break;
case IPFIX_TYPEID_tcpControlBits:
if (parseTcpFlags(pattern, &ruleField->pattern, &ruleField->type.length) != 0) {
msg(MSG_ERROR, "Bad TCP flags pattern \"%s\" in %s, l.%d", pattern, fname, lineNo);
continue;
}
break;
default:
msg(MSG_ERROR, "Fields of type \"%s\" cannot be matched against a pattern %s, l.%d", field, fname, lineNo);
continue;
break;
}
currentRule->field[currentRule->fieldCount++] = ruleField;
ruleField = new Rule::Field();
}
if (currentRule->fieldCount > 0) {
rule[count++] = currentRule;
currentRule = new Rule();
}
fclose(f);
/* tidy up */
delete ruleField;
delete currentRule;
}
bool operator==(const Rules &rhs, const Rules &lhs) {
if (rhs.count != lhs.count) return false;

View File

@ -36,7 +36,6 @@
class Rules {
public:
Rules();
Rules(char* fname);
~Rules();
friend bool operator==(const Rules &rhs, const Rules &lhs);
friend bool operator!=(const Rules &rhs, const Rules &lhs);

View File

@ -31,15 +31,7 @@ class TestSink : public IpfixRecordDestination {
uint8_t inTemplateId = record->templateInfo->templateId - 256;
uint8_t inTypeId = record->templateInfo->fieldInfo[0].type.id;
uint8_t inData = record->data[0];
if ((record->templateInfo->setId == TemplateInfo::IpfixDataTemplate) && (record->templateInfo->dataCount > 0)) {
uint8_t inDataTemplateTypeId = record->templateInfo->dataInfo[0].type.id;
uint8_t inDataTemplate = record->templateInfo->data[0];
msg(MSG_DEBUG, "Received DataDataRecord: %d, %d, %d, %d, %d, %d", inSourceID, inTemplateId, inTypeId, inData, inDataTemplateTypeId, inDataTemplate);
if (inData != inDataTemplateTypeId) ERROR("IpfixRecord got corrupted: inData != inDataTemplateTypeId");
if (inData != inDataTemplate) ERROR("IpfixRecord got corrupted: inData != inDataTemplate");
} else {
msg(MSG_DEBUG, "Received DataRecord: %d, %d, %d, %d", inSourceID, inTemplateId, inTypeId, inData);
}
msg(MSG_DEBUG, "Received DataRecord: %d, %d, %d, %d", inSourceID, inTemplateId, inTypeId, inData);
if (checkSourceId) if (inSourceID != inTemplateId) ERROR("SourceID or TemplateInfo got corrupted: inSourceID != inTemplateId");
if (inTemplateId != inTypeId) ERROR("TemplateInfo got corrupted: inTemplateId != inTypeId");
if (inData != inTemplateId) ERROR("IpfixRecord got corrupted: inData != inTemplateId");
@ -83,28 +75,6 @@ boost::shared_ptr<TemplateInfo> createTestTemplate(uint8_t magic_number) {
return testTemplate;
}
boost::shared_ptr<TemplateInfo> createTestDataTemplate(uint8_t magic_number) {
boost::shared_ptr<TemplateInfo> testTemplate(new TemplateInfo);
testTemplate->templateId = magic_number + 256;
testTemplate->setId = TemplateInfo::IpfixDataTemplate;
testTemplate->preceding = 0;
testTemplate->fieldCount = 1;
testTemplate->fieldInfo = (TemplateInfo::FieldInfo*)malloc(testTemplate->fieldCount * sizeof(TemplateInfo::FieldInfo));
testTemplate->dataCount = 1;
testTemplate->dataInfo = (TemplateInfo::FieldInfo*)malloc(testTemplate->fieldCount * sizeof(TemplateInfo::FieldInfo));
testTemplate->data = (uint8_t*)malloc(1); testTemplate->data[0] = magic_number;
testTemplate->fieldInfo[0].type.id = magic_number;
testTemplate->fieldInfo[0].type.length = 1;
testTemplate->fieldInfo[0].type.enterprise = 0;
testTemplate->fieldInfo[0].offset = 0;
testTemplate->dataInfo[0].type.id = magic_number;
testTemplate->dataInfo[0].type.length = 1;
testTemplate->dataInfo[0].type.enterprise = 0;
testTemplate->dataInfo[0].offset = 0;
return testTemplate;
}
boost::shared_ptr<IpfixRecord::SourceID> createTestSourceId(uint8_t magic_number) {
boost::shared_ptr<IpfixRecord::SourceID> testSourceId(new IpfixRecord::SourceID);
testSourceId->observationDomainId = 0xdeadbeef;
@ -138,18 +108,6 @@ IpfixTemplateDestructionRecord* createTestTemplateDestructionRecord(uint8_t magi
return testRecord;
}
IpfixDataRecord* createTestDataDataRecord(uint8_t magic_number, boost::shared_ptr<IpfixRecord::SourceID> sourceId, boost::shared_ptr<TemplateInfo> dataTemplateInfo) {
static InstanceManager<IpfixDataRecord> im("IpfixDataDataRecord");
IpfixDataRecord* testRecord = im.getNewInstance();
testRecord->sourceID = sourceId;
testRecord->templateInfo = dataTemplateInfo;
testRecord->dataLength = 1;
testRecord->message = createTestData(magic_number);
testRecord->data = testRecord->message.get();
return testRecord;
}
IpfixTemplateRecord* createTestTemplateRecord(uint8_t magic_number, boost::shared_ptr<TemplateInfo> templateInfo) {
static InstanceManager<IpfixTemplateRecord> im("IpfixTemplateRecord");
IpfixTemplateRecord* testRecord = im.getNewInstance();
@ -158,22 +116,6 @@ IpfixTemplateRecord* createTestTemplateRecord(uint8_t magic_number, boost::share
return testRecord;
}
IpfixTemplateRecord* createTestDataTemplateRecord(uint8_t magic_number, boost::shared_ptr<TemplateInfo> dataTemplateInfo) {
static InstanceManager<IpfixTemplateRecord> im("IpfixDataTemplateRecord");
IpfixTemplateRecord* testRecord = im.getNewInstance();
testRecord->templateInfo = dataTemplateInfo;
return testRecord;
}
IpfixTemplateDestructionRecord* createTestDataTemplateDestructionRecord(uint8_t magic_number, boost::shared_ptr<TemplateInfo> dataTemplateInfo) {
static InstanceManager<IpfixTemplateDestructionRecord> im("IpfixDataTemplateDestructionRecord");
IpfixTemplateDestructionRecord* testRecord = im.getNewInstance();
testRecord->templateInfo = dataTemplateInfo;
return testRecord;
}
void test_module_coupling() {
std::cout << "Testing: Concentrator module coupling..." << std::endl;
@ -246,8 +188,8 @@ void test_ipfixlolib_rawdir() {
std::vector<IpfixDataRecord*> testDataRecords;
for (uint8_t magic_number = 0; magic_number < 16; magic_number++) {
boost::shared_ptr<IpfixRecord::SourceID> testSourceId = createTestSourceId(magic_number);
boost::shared_ptr<TemplateInfo> dataTemplateInfo = createTestDataTemplate(magic_number);
IpfixTemplateRecord* dtr = createTestDataTemplateRecord(magic_number, dataTemplateInfo);
boost::shared_ptr<TemplateInfo> dataTemplateInfo = createTestTemplate(magic_number);
IpfixTemplateRecord* dtr = createTestTemplateRecord(magic_number, dataTemplateInfo);
ipfixRawdirWriter.receive(dtr);
testDataRecords.push_back(createTestDataRecord(magic_number, testSourceId, dataTemplateInfo));
@ -261,7 +203,7 @@ void test_ipfixlolib_rawdir() {
// be nice
for (uint8_t magic_number = 0; magic_number < 16; magic_number++) {
ipfixRawdirWriter.receive(createTestDataTemplateDestructionRecord(magic_number, testDataRecords[magic_number]->templateInfo));
ipfixRawdirWriter.receive(createTestTemplateDestructionRecord(magic_number, testDataRecords[magic_number]->templateInfo));
}
// give modules a chance to process their queues