Commit message: Fix potential unsigned integer underflow
CVE: CVE-2019-14459
CWE: CWE-190
Vulnerability description: nfdump 1.6.17 and earlier is affected by an integer overflow in the function Process_ipfix_template_withdraw in ipfix.c that can be abused in order to crash the process remotely (denial of service).

Project: nfdump
File: ipfix.c

static int CheckSequenceMap(input_translation_t *table) {

	if ( table->number_of_sequences < table->max_number_of_sequences )
		return 1;

	dbg_printf("Extend sequence map %u -> ", table->max_number_of_sequences);
	void *p = realloc(table->sequence,  (table->max_number_of_sequences + 1) * sizeof(sequence_map_t));
	if ( !p ) {
		LogError("Process_ipfix: realloc() at %s line %d: %s", 
			__FILE__, __LINE__, strerror (errno));
		dbg_printf("\nProcess_ipfix: realloc() at %s line %d: %s", 
			__FILE__, __LINE__, strerror (errno));
		return 0;
	}
	table->sequence = p;
	table->max_number_of_sequences += 1;
	dbg_printf("%u\n", table->max_number_of_sequences);
	return 1;

} // End of CheckSequenceMap

Project: nfdump

int Init_IPFIX(void) {
int i;

	cache.lookup_info	    = (struct element_param_s *)calloc(65536, sizeof(struct element_param_s));
	cache.common_extensions = (uint32_t *)malloc((Max_num_extensions+1)*sizeof(uint32_t));
	if ( !cache.common_extensions || !cache.lookup_info ) {
		LogError("Process_ipfix: Panic! malloc(): %s line %d: %s", __FILE__, __LINE__, strerror (errno));
		return 0;
	}

	for (i=1; ipfix_element_map[i].id != 0; i++ ) {
		uint32_t Type = ipfix_element_map[i].id;
		if ( cache.lookup_info[Type].index == 0 ) 
			cache.lookup_info[Type].index  = i;
	}
	cache.max_ipfix_elements = i;
	cache.input_order = NULL;

	LogError("Init IPFIX: Max number of IPFIX tags: %u", cache.max_ipfix_elements);

	return 1;

} // End of Init_IPFIX

Project: nfdump

static void InsertSampler(FlowSource_t *fs, exporter_ipfix_domain_t *exporter, int32_t id, uint16_t mode, uint32_t interval) {
generic_sampler_t *sampler;

	dbg_printf("[%u] Insert Sampler: Exporter is 0x%llu\n", exporter->info.id, (long long unsigned)exporter);
	if ( !exporter->sampler ) {
		sampler = (generic_sampler_t *)malloc(sizeof(generic_sampler_t));
		if ( !sampler ) {
			LogError( "Process_v9: Panic! malloc(): %s line %d: %s", __FILE__, __LINE__, strerror (errno));
			return;
		}

		sampler->info.header.type = SamplerInfoRecordype;
		sampler->info.header.size = sizeof(sampler_info_record_t);
		sampler->info.exporter_sysid = exporter->info.sysid;
		sampler->info.id	   = id;
		sampler->info.mode	 = mode;
		sampler->info.interval = interval;
		sampler->next		  = NULL;
		exporter->sampler = sampler;

		FlushInfoSampler(fs, &(sampler->info));
		LogInfo( "Add new sampler: ID: %i, mode: %u, interval: %u\n", 
			id, mode, interval);
		dbg_printf("Add new sampler: ID: %i, mode: %u, interval: %u\n", 
			id, mode, interval);

	} else {
		sampler = exporter->sampler;
		while ( sampler ) {
			if ( sampler->info.id == id ) {
				dbg_printf("Update existing sampler id: %i, mode: %u, interval: %u\n", 
					id, mode, interval);

				if ( mode != sampler->info.mode || interval != sampler->info.interval ) {
					FlushInfoSampler(fs, &(sampler->info));
					sampler->info.mode	 = mode;
					sampler->info.interval = interval;
					LogInfo( "Update existing sampler id: %i, mode: %u, interval: %u\n", 
						id, mode, interval);
				} else {
					dbg_printf("Sampler unchanged!\n");
				}

				break;
			}

			if ( sampler->next == NULL ) {
				sampler->next = (generic_sampler_t *)malloc(sizeof(generic_sampler_t));
				if ( !sampler->next ) {
					LogError( "Process_v9: Panic! malloc(): %s line %d: %s", __FILE__, __LINE__, strerror (errno));
					return;
				}
				sampler = sampler->next;

				sampler->info.header.type	 = SamplerInfoRecordype;
				sampler->info.header.size	 = sizeof(sampler_info_record_t);
				sampler->info.exporter_sysid = exporter->info.sysid;
				sampler->info.id	   	= id;
				sampler->info.mode		= mode;
				sampler->info.interval	= interval;
				sampler->next			= NULL;

				FlushInfoSampler(fs, &(sampler->info));

				LogInfo( "Append new sampler: ID: %u, mode: %u, interval: %u\n", 
					id, mode, interval);
				dbg_printf("Append new sampler: ID: %u, mode: %u, interval: %u\n", 
					id, mode, interval);
				break;
			}

			sampler = sampler->next;
		}
	} 
	
} // End of InsertSampler

Project: nfdump
File: ipfix.c

static void InsertStdSamplerOffset( FlowSource_t *fs, uint16_t id, uint16_t offset_std_sampler_interval, uint16_t offset_std_sampler_algorithm) {
option_offset_t **t;

	t = &(fs->option_offset_table);
	while ( *t ) {
		if ( (*t)->id == id ) { // table already known to us - update data
			dbg_printf("Found existing std sampling info in template %i\n", id);
			break;
		}
	
		t = &((*t)->next);
	}

	if ( *t == NULL ) { // new table
		dbg_printf("Allocate new std sampling info from template %i\n", id);
		*t = (option_offset_t *)calloc(1, sizeof(option_offset_t));
		if ( !*t ) {
			LogError("malloc() allocation error at %s line %u: %s" , __FILE__, __LINE__, strerror (errno));
			return ;
		} 
		LogInfo("Process_v9: New std sampler: interval: %i, algorithm: %i", 
			offset_std_sampler_interval, offset_std_sampler_algorithm);
	}   // else existing table

	dbg_printf("Insert/Update sampling info from template %i\n", id);
	SetFlag((*t)->flags, HAS_STD_SAMPLER_DATA);
	(*t)->id				= id;
	(*t)->offset_id			= 0;
	(*t)->offset_mode		= 0;
	(*t)->offset_interval	= 0;
	(*t)->offset_std_sampler_interval   = offset_std_sampler_interval;
	(*t)->offset_std_sampler_algorithm  = offset_std_sampler_algorithm;
	
} // End of InsertStdSamplerOffset

Project: nfdump

void Process_IPFIX(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs) {
exporter_ipfix_domain_t	*exporter;
ssize_t				size_left;
uint32_t			ExportTime, Sequence, flowset_length;
ipfix_header_t		*ipfix_header;
void				*flowset_header;

#ifdef DEVEL
static uint32_t		packet_cntr = 0;
uint32_t 			ObservationDomain;
#endif

	size_left 	 = in_buff_cnt;
	if ( size_left < IPFIX_HEADER_LENGTH ) {
		LogError("Process_ipfix: Too little data for ipfix packet: '%lli'", (long long)size_left);
		return;
	}

	ipfix_header = (ipfix_header_t *)in_buff;
	ExportTime 			 = ntohl(ipfix_header->ExportTime);
	Sequence 			 = ntohl(ipfix_header->LastSequence);

#ifdef DEVEL
	ObservationDomain 	 = ntohl(ipfix_header->ObservationDomain);
	packet_cntr++;
	printf("Next packet: %u\n", packet_cntr);
#endif

	exporter	= GetExporter(fs, ipfix_header);
	if ( !exporter ) {
		LogError("Process_ipfix: Exporter NULL: Abort ipfix record processing");
		return;
	}
	exporter->packets++;
	flowset_header	= (void *)ipfix_header + IPFIX_HEADER_LENGTH;
	size_left 	   -= IPFIX_HEADER_LENGTH;

	dbg_printf("\n[%u] process packet: %u, exported: %s, TemplateRecords: %llu, DataRecords: %llu, buffer: %li \n", 
		ObservationDomain, packet_cntr, UNIX2ISO(ExportTime), (long long unsigned)exporter->TemplateRecords, 
		(long long unsigned)exporter->DataRecords, size_left);

	dbg_printf("[%u] Sequence: %u\n", ObservationDomain, Sequence);

	if ( Sequence != exporter->PacketSequence ) {
		if ( exporter->DataRecords != 0 ) {
			fs->nffile->stat_record->sequence_failure++;
			exporter->sequence_failure++;
			dbg_printf("[%u] Sequence check failed: last seq: %u, seq %u\n", 
				exporter->info.id, Sequence, exporter->PacketSequence);
			/* maybee to noise on buggy exporters
			LogError("Process_ipfix [%u] Sequence error: last seq: %u, seq %u\n", 
				info.id, exporter->LastSequence, Sequence);
			*/
		} else {
			dbg_printf("[%u] Sync Sequence: %u\n", exporter->info.id, Sequence);
		}
		exporter->PacketSequence = Sequence;
	} else {
		dbg_printf("[%u] Sequence check ok\n", exporter->info.id);
	}

	flowset_length = 0;
	while (size_left) {
		uint16_t	flowset_id;

		if ( size_left && size_left < 4 ) {
			size_left = 0;
			continue;
		}

		flowset_header = flowset_header + flowset_length;

		flowset_id 		= GET_FLOWSET_ID(flowset_header);
		flowset_length 	= GET_FLOWSET_LENGTH(flowset_header);

		dbg_printf("Process_ipfix: Next flowset id %u, length %u.\n", flowset_id, flowset_length);

		if ( flowset_length == 0 ) {
			/* 	this should never happen, as 4 is an empty flowset 
				and smaller is an illegal flowset anyway ...
				if it happends, we can't determine the next flowset, so skip the entire export packet
			 */
			LogError("Process_ipfix: flowset zero length error.");
			dbg_printf("Process_ipfix: flowset zero length error.\n");
			return;

		}

		if ( flowset_length <= 4 ) {
			size_left = 0;
			continue;
		}

		if ( flowset_length > size_left ) {
			LogError("Process_ipfix: flowset length error. Expected bytes: %u > buffersize: %lli", 
				flowset_length, (long long)size_left);
			size_left = 0;
			continue;
		}


		switch (flowset_id) {
			case IPFIX_TEMPLATE_FLOWSET_ID:
				exporter->TemplateRecords++;
				dbg_printf("Process template flowset, length: %u\n", flowset_length);
				Process_ipfix_templates(exporter, flowset_header, flowset_length, fs);
				break;
			case IPFIX_OPTIONS_FLOWSET_ID:
				exporter->TemplateRecords++;
				dbg_printf("Process option template flowset, length: %u\n", flowset_length);
				Process_ipfix_option_templates(exporter, flowset_header, fs);
				break;
			default: {
				if ( flowset_id < IPFIX_MIN_RECORD_FLOWSET_ID ) {
					dbg_printf("Invalid flowset id: %u. Skip flowset\n", flowset_id);
					LogError("Process_ipfix: Invalid flowset id: %u. Skip flowset", flowset_id);
				} else {
					input_translation_t *table;
					dbg_printf("Process data flowset, length: %u\n", flowset_length);
					table = GetTranslationTable(exporter, flowset_id);
					if ( table ) {
						Process_ipfix_data(exporter, ExportTime, flowset_header, fs, table);
						exporter->DataRecords++;
					} else if ( HasOptionTable(fs, flowset_id) ) {
						Process_ipfix_option_data(exporter, flowset_header, fs);
					} else {
						dbg_printf("Process ipfix: [%u] No table for id %u -> Skip record\n", 
							exporter->info.id, flowset_id);
					}

				}
			}
		} // End of switch

		size_left -= flowset_length;

	} // End of while

} // End of Process_IPFIX

Project: nfdump

static void Process_ipfix_data(exporter_ipfix_domain_t *exporter, uint32_t ExportTime, void *data_flowset, FlowSource_t *fs, input_translation_t *table ){
uint64_t			sampling_rate;
uint32_t			size_left;
uint8_t				*in, *out;
int					i;
char				*string;

	size_left = GET_FLOWSET_LENGTH(data_flowset) - 4; // -4 for data flowset header -> id and length

	in  	  = (uint8_t *)(data_flowset + 4);	// skip flowset header

	dbg_printf("[%u] Process data flowset size: %u\n", exporter->info.id, size_left);


	sampling_rate = 1;

	generic_sampler_t *sampler = exporter->sampler;
	while ( sampler && sampler->info.id != -1 ) 
		sampler = sampler->next;

	if ( sampler ) {
		sampling_rate = sampler->info.interval;
		dbg_printf("[%u] Std sampling available for this flow source: Rate: %llu\n", exporter->info.id, (long long unsigned)sampling_rate);
	} else {
		sampling_rate = default_sampling;
		dbg_printf("[%u] No Sampling record found\n", exporter->info.id);
	}

	if ( overwrite_sampling > 0 )  {
		sampling_rate = overwrite_sampling;
		dbg_printf("[%u] Hard overwrite sampling rate: %llu\n", exporter->info.id, (long long unsigned)sampling_rate);
	} 

	if ( sampling_rate != 1 )
		SetFlag(table->flags, FLAG_SAMPLED);

	while (size_left) {
		int input_offset;
		common_record_t		*data_record;

		if ( size_left < 4 ) {	// rounding pads
			size_left = 0;
			continue;
		}

		if ( !CheckBufferSpace(fs->nffile, table->output_record_size) ) {
			LogError("Process_ipfix: output buffer size error. Abort ipfix record processing");
			dbg_printf("Process_ipfix: output buffer size error. Abort ipfix record processing");
			return;
		}
		processed_records++;
		exporter->PacketSequence++;

		data_record	= (common_record_t *)fs->nffile->buff_ptr;
		out 	  = (uint8_t *)data_record;

		dbg_printf("[%u] Process data record: %u addr: %llu, buffer size_left: %u\n", 
			exporter->info.id, processed_records, (long long unsigned)((ptrdiff_t)in - (ptrdiff_t)data_flowset), 
			size_left);

		data_record->flags 		    = table->flags;
		data_record->size  		    = table->output_record_size;
		data_record->type  		    = CommonRecordType;
	  	data_record->ext_map	    = table->extension_info.map->map_id;
		data_record->exporter_sysid = exporter->info.sysid;
		data_record->reserved 		= 0;

		table->flow_start 		    = 0;
		table->flow_end 		    = 0;
		table->packets 		  	    = 0;
		table->bytes 		  	    = 0;
		table->out_packets 	  	    = 0;
		table->out_bytes 	  	    = 0;

		input_offset = 0;
		for ( i=0; i<table->number_of_sequences; i++ ) {
			int output_offset = table->sequence[i].output_offset;
			void *stack = table->sequence[i].stack;

			if ( input_offset > size_left ) {
				LogError("Process ipfix: buffer overrun!! input_offset: %i > size left data buffer: %u\n", input_offset, size_left);
				return;
			} 

			switch (table->sequence[i].id) {
				case nop:
					break;
				case dyn_skip: {
					uint16_t skip = in[input_offset];
					if ( skip < 255 ) {
						input_offset += (skip+1);
					} else {
						skip = Get_val16((void *)&in[input_offset+1]);
						input_offset += (skip+3);
					}
					} break;
				case move8:
					out[output_offset] = in[input_offset];
					break;
				case move16:
					*((uint16_t *)&out[output_offset]) = Get_val16((void *)&in[input_offset]);
					break;
				case move32:
					*((uint32_t *)&out[output_offset]) = Get_val32((void *)&in[input_offset]);
					break;
				case move40:
					/* 64bit access to potentially unaligned output buffer. use 2 x 32bit for _LP64 CPUs */
					{ type_mask_t t;

						t.val.val64 = Get_val40((void *)&in[input_offset]);
						*((uint32_t *)&out[output_offset]) 	 = t.val.val32[0];
						*((uint32_t *)&out[output_offset+4]) = t.val.val32[1];
					}
					break;
				case move48:
					/* 64bit access to potentially unaligned output buffer. use 2 x 32bit for _LP64 CPUs */
					{ type_mask_t t;
						t.val.val64 = Get_val48((void *)&in[input_offset]);
						*((uint32_t *)&out[output_offset]) 	 = t.val.val32[0];
						*((uint32_t *)&out[output_offset+4]) = t.val.val32[1];
					}
					break;
				case move56:
					/* 64bit access to potentially unaligned output buffer. use 2 x 32bit for _LP64 CPUs */
					{ type_mask_t t;

						t.val.val64 = Get_val56((void *)&in[input_offset]);
						*((uint32_t *)&out[output_offset]) 	 = t.val.val32[0];
						*((uint32_t *)&out[output_offset+4]) = t.val.val32[1];
					}
					break;
				case move64: 
					{ type_mask_t t;
						t.val.val64 = Get_val64((void *)&in[input_offset]);

						*((uint32_t *)&out[output_offset]) 	 = t.val.val32[0];
						*((uint32_t *)&out[output_offset+4]) = t.val.val32[1];
					} break;
				case move128: 
					/* 64bit access to potentially unaligned output buffer. use 2 x 32bit for _LP64 CPUs */
					{ type_mask_t t;
					  
						t.val.val64 = Get_val64((void *)&in[input_offset]);
						*((uint32_t *)&out[output_offset]) 	  = t.val.val32[0];
						*((uint32_t *)&out[output_offset+4])  = t.val.val32[1];

						t.val.val64 = Get_val64((void *)&in[input_offset+8]);
						*((uint32_t *)&out[output_offset+8])  = t.val.val32[0];
						*((uint32_t *)&out[output_offset+12]) = t.val.val32[1];
					} break;
				case move32_sampling:
					/* 64bit access to potentially unaligned output buffer. use 2 x 32bit for _LP64 CPUs */
					{ type_mask_t t;
						t.val.val64 = Get_val32((void *)&in[input_offset]);
						t.val.val64 *= sampling_rate;
						*((uint32_t *)&out[output_offset]) 	 = t.val.val32[0];
						*((uint32_t *)&out[output_offset+4]) = t.val.val32[1];
					  	*(uint64_t *)stack = t.val.val64;
					} break;
				case move64_sampling:
					/* 64bit access to potentially unaligned output buffer. use 2 x 32bit for _LP64 CPUs */
					{ type_mask_t t;
						t.val.val64 = Get_val64((void *)&in[input_offset]);

						t.val.val64 *= sampling_rate;
						*((uint32_t *)&out[output_offset]) 	 = t.val.val32[0];
						*((uint32_t *)&out[output_offset+4]) = t.val.val32[1];
					  	*(uint64_t *)stack = t.val.val64;
					} break;
				case Time64Mili:
					{ uint64_t DateMiliseconds = Get_val64((void *)&in[input_offset]);
					  *(uint64_t *)stack = DateMiliseconds;

					} break;
				case TimeUnix:
					{ uint64_t DateSeconds = Get_val32((void *)&in[input_offset]);
					  *(uint64_t *)stack = DateSeconds *1000LL;

					} break;
				case TimeDeltaMicro:
					{ uint64_t DeltaMicroSec = Get_val32((void *)&in[input_offset]);
					  *(uint64_t *)stack = ((1000000LL * (uint64_t)ExportTime) - DeltaMicroSec) / 1000LL;

					} break;
				case saveICMP:
					*(uint32_t *)stack = Get_val16((void *)&in[input_offset]);
					break;
				case move_mpls:
					*((uint32_t *)&out[output_offset]) = Get_val24((void *)&in[input_offset]);
					break;
				case move_flags: {
					uint16_t flags = Get_val16((void *)&in[input_offset]);
					out[output_offset] = flags & 0xFF;
					} break;
				case move_mac:
					/* 64bit access to potentially unaligned output buffer. use 2 x 32bit for _LP64 CPUs */
					{ type_mask_t t;

						t.val.val64 = Get_val48((void *)&in[input_offset]);
						*((uint32_t *)&out[output_offset])   = t.val.val32[0];
						*((uint32_t *)&out[output_offset+4]) = t.val.val32[1];
					}
					break;
				case zero8:
					out[output_offset] = 0;
					break;
				case zero16:
					*((uint16_t *)&out[output_offset]) = 0;
					break;
				case zero32:
					*((uint32_t *)&out[output_offset]) = 0;
					break;
				case zero64: 
						*((uint64_t *)&out[output_offset]) = 0;
					 break;
				case zero128: 
						*((uint64_t *)&out[output_offset]) = 0;
						*((uint64_t *)&out[output_offset+8]) = 0;
					break;
				
				default:
					LogError("Process_ipfix: Software bug! Unknown Sequence: %u. at %s line %d", 
						table->sequence[i].id, __FILE__, __LINE__);
					dbg_printf("Software bug! Unknown Sequence: %u. at %s line %d\n", 
						table->sequence[i].id, __FILE__, __LINE__);
			}
			input_offset += (table->sequence[i].input_length + table->sequence[i].skip_count);
		}

		if ( data_record->prot == IPPROTO_ICMP || data_record->prot == IPPROTO_ICMPV6 ) {
			if ( table->icmpTypeCodeIPv4 ) {
				data_record->srcport = 0;
				data_record->dstport = table->icmpTypeCodeIPv4;
			}
		}

		if ( table->received_offset ) {
			type_mask_t t;
			t.val.val64 = (uint64_t)((uint64_t)fs->received.tv_sec * 1000LL) + (uint64_t)((uint64_t)fs->received.tv_usec / 1000LL);
				*((uint32_t *)&out[table->received_offset])   = t.val.val32[0];
				*((uint32_t *)&out[table->received_offset+4]) = t.val.val32[1];
		}

		data_record->first 		= table->flow_start / 1000;
		data_record->msec_first = table->flow_start % 1000;

		data_record->last 		= table->flow_end / 1000;
		data_record->msec_last	= table->flow_end % 1000;

		if ( table->flow_start < fs->first_seen )
			fs->first_seen = table->flow_start;
		if ( table->flow_end > fs->last_seen )
			fs->last_seen = table->flow_end;

		if ( table->router_ip_offset ) {
			int output_offset = table->router_ip_offset;
			if ( exporter->info.sa_family == PF_INET6 ) {
				type_mask_t t;
					  
				t.val.val64 = exporter->info.ip.V6[0];
				*((uint32_t *)&out[output_offset]) 	  = t.val.val32[0];
				*((uint32_t *)&out[output_offset+4])  = t.val.val32[1];

				t.val.val64 = exporter->info.ip.V6[1];
				*((uint32_t *)&out[output_offset+8])  = t.val.val32[0];
				*((uint32_t *)&out[output_offset+12]) = t.val.val32[1];
			} else {
				*((uint32_t *)&out[output_offset]) = exporter->info.ip.V4;
			}
		}

		switch (data_record->prot ) { // switch protocol of
			case IPPROTO_ICMP:
				fs->nffile->stat_record->numflows_icmp++;
				fs->nffile->stat_record->numpackets_icmp  += table->packets;
				fs->nffile->stat_record->numbytes_icmp    += table->bytes;
				fs->nffile->stat_record->numpackets_icmp  += table->out_packets;
				fs->nffile->stat_record->numbytes_icmp    += table->out_bytes;
				break;
			case IPPROTO_TCP:
				fs->nffile->stat_record->numflows_tcp++;
				fs->nffile->stat_record->numpackets_tcp   += table->packets;
				fs->nffile->stat_record->numbytes_tcp     += table->bytes;
				fs->nffile->stat_record->numpackets_tcp   += table->out_packets;
				fs->nffile->stat_record->numbytes_tcp     += table->out_bytes;
				break;
			case IPPROTO_UDP:
				fs->nffile->stat_record->numflows_udp++;
				fs->nffile->stat_record->numpackets_udp   += table->packets;
				fs->nffile->stat_record->numbytes_udp     += table->bytes;
				fs->nffile->stat_record->numpackets_udp   += table->out_packets;
				fs->nffile->stat_record->numbytes_udp     += table->out_bytes;
				break;
			default:
				fs->nffile->stat_record->numflows_other++;
				fs->nffile->stat_record->numpackets_other += table->packets;
				fs->nffile->stat_record->numbytes_other   += table->bytes;
				fs->nffile->stat_record->numpackets_other += table->out_packets;
				fs->nffile->stat_record->numbytes_other   += table->out_bytes;
		}
		exporter->flows++;
		fs->nffile->stat_record->numflows++;
		fs->nffile->stat_record->numpackets	+= table->packets;
		fs->nffile->stat_record->numbytes	+= table->bytes;
		fs->nffile->stat_record->numpackets	+= table->out_packets;
		fs->nffile->stat_record->numbytes	+= table->out_bytes;
	
		if ( verbose ) {
			master_record_t master_record;
			memset((void *)&master_record, 0, sizeof(master_record_t));
			ExpandRecord_v2((common_record_t *)data_record, &(table->extension_info), &(exporter->info), &master_record);
		 	format_file_block_record(&master_record, &string, 0);
			printf("%s\n", string);
		}

		fs->nffile->block_header->size  += data_record->size;
		fs->nffile->block_header->NumRecords++;
		fs->nffile->buff_ptr	= (common_record_t *)((pointer_addr_t)data_record + data_record->size);

		dbg_printf("Adjust input stream offset: %u\n", input_offset);
		if ( input_offset > size_left ) {
			LogError("Process ipfix: buffer overrun!! input_offset: %i > size left data buffer: %u\n", input_offset, size_left);
			return;
		} 
		size_left 		   -= input_offset;
		in  	  		   += input_offset;

		if ( fs->nffile->block_header->size  > BUFFSIZE ) {
			LogError("### Software error ###: %s line %d", __FILE__, __LINE__);
			LogError("Process ipfix: Output buffer overflow! Flush buffer and skip records.");
			LogError("Buffer size: %u > %u", fs->nffile->block_header->size, BUFFSIZE);

			fs->nffile->block_header->size 		= 0;
			fs->nffile->block_header->NumRecords = 0;
			fs->nffile->buff_ptr = (void *)((pointer_addr_t)fs->nffile->block_header + sizeof(data_block_header_t) );
			return;
		}

	}

} // End of Process_ipfix_data

Project: nfdump

static void  Process_ipfix_option_data(exporter_ipfix_domain_t *exporter, void *data_flowset, FlowSource_t *fs) {
option_offset_t *offset_table;
uint32_t	id;
uint8_t	 *in;

	id  = GET_FLOWSET_ID(data_flowset);

	offset_table = fs->option_offset_table;
	while ( offset_table && offset_table->id != id )
		offset_table = offset_table->next;

	if ( !offset_table ) {
		LogError( "Process_ipfix: Panic! - No Offset table found! : %s line %d", __FILE__, __LINE__);
		return;
	}

#ifdef DEVEL
	uint32_t size_left = GET_FLOWSET_LENGTH(data_flowset) - 4; // -4 for data flowset header -> id and length
	dbg_printf("[%u] Process option data flowset size: %u\n", exporter->info.id, size_left);
#endif

	in	= (uint8_t *)(data_flowset + 4);  // skip flowset header

	if ( TestFlag(offset_table->flags, HAS_SAMPLER_DATA) ) {
		int32_t  id;
		uint16_t mode;
		uint32_t interval;
		if (offset_table->sampler_id_length == 2) {
			id = Get_val16((void *)&in[offset_table->offset_id]);
		} else {
			id = in[offset_table->offset_id];
		}

		mode = offset_table->offset_mode ? in[offset_table->offset_mode] : 0;
		interval = Get_val32((void *)&in[offset_table->offset_interval]); 
	
		InsertSampler(fs, exporter, id, mode, interval);

		dbg_printf("Extracted Sampler data:\n");
		dbg_printf("Sampler ID	  : %u\n", id);
		dbg_printf("Sampler mode	: %u\n", mode);
		dbg_printf("Sampler interval: %u\n", interval);
	}

	if ( TestFlag(offset_table->flags, HAS_STD_SAMPLER_DATA) ) {
		int32_t  id	   = -1;
		uint16_t mode	 = offset_table->offset_std_sampler_algorithm ? in[offset_table->offset_std_sampler_algorithm] : 0;
		uint32_t interval = Get_val32((void *)&in[offset_table->offset_std_sampler_interval]);

 		InsertSampler(fs, exporter, id, mode, interval);

		dbg_printf("Extracted Std Sampler data:\n");
		dbg_printf("Sampler ID	   : %i\n", id);
		dbg_printf("Sampler algorithm: %u\n", mode);
		dbg_printf("Sampler interval : %u\n", interval);

		dbg_printf("Set std sampler: algorithm: %u, interval: %u\n", 
				mode, interval);
	}
	processed_records++;

} // End of Process_ipfix_option_data

Project: nfdump

static void Process_ipfix_option_templates(exporter_ipfix_domain_t *exporter, void *option_template_flowset, FlowSource_t *fs) {
uint8_t		*DataPtr;
uint32_t	size_left, size_required, i;
uint16_t	id, field_count, scope_field_count, offset;
uint16_t	offset_std_sampler_interval, offset_std_sampler_algorithm, found_std_sampling;

	i = 0;	// keep compiler happy
	size_left 		  = GET_FLOWSET_LENGTH(option_template_flowset) - 4; // -4 for flowset header -> id and length
	if ( size_left < 6 ) {
		LogError("Process_ipfix: [%u] option template length error: size left %u too small for an options template", 
			exporter->info.id, size_left);
		return;
	}

	DataPtr   		  = option_template_flowset + 4;
	id 	  			  = GET_OPTION_TEMPLATE_ID(DataPtr); 
	field_count 	  = GET_OPTION_TEMPLATE_FIELD_COUNT(DataPtr);
	scope_field_count = GET_OPTION_TEMPLATE_SCOPE_FIELD_COUNT(DataPtr);
	DataPtr   += 6;
	size_left -= 6;

	dbg_printf("Decode Option Template. id: %u, field count: %u, scope field count: %u\n",
		id, field_count, scope_field_count);

	if ( scope_field_count == 0  ) {
		LogError("Process_ipfx: [%u] scope field count error: length must not be zero", 
			exporter->info.id);
		dbg_printf("scope field count error: length must not be zero\n");
		return;
	}

	size_required = 2 * field_count * sizeof(uint16_t);
	dbg_printf("Size left: %u, size required: %u\n", size_left, size_required);
	if ( size_left < size_required ) {
		LogError("Process_ipfix: [%u] option template length error: size left %u too small for %u scopes length and %u options length", 
			exporter->info.id, size_left, field_count, scope_field_count);
		dbg_printf("option template length error: size left %u too small for field_count %u\n", 
			size_left, field_count);
		return;
	}

	if ( scope_field_count == 0  ) {
		LogError("Process_ipfxi: [%u] scope field count error: length must not be zero", 
			exporter->info.id);
		return;
	}

	offset_std_sampler_interval  = 0;
	offset_std_sampler_algorithm = 0;
	found_std_sampling			 = 0;
	offset = 0;

	for ( i=0; i<scope_field_count; i++ ) {
		uint16_t id, length;
		int Enterprise;

		if ( size_left && size_left < 4 ) {
			LogError("Process_ipfix [%u] Template size error at %s line %u" , 
				exporter->info.id, __FILE__, __LINE__, strerror (errno));
			return;
		}
		id 	   = Get_val16(DataPtr); DataPtr += 2;
		length = Get_val16(DataPtr); DataPtr += 2;
		size_left -= 4;
		Enterprise = id & 0x8000 ? 1 : 0;
		if ( Enterprise ) {
			size_required += 4;
			if ( size_left < 4 ) {
				LogError("Process_ipfix: [%u] option template length error: size left %u too small", 
					exporter->info.id, size_left);
				dbg_printf("option template length error: size left %u too small\n", size_left);
				return;
			}
			DataPtr += 4;
			size_left -= 4;
			dbg_printf(" [%i] Enterprise: 1, scope id: %u, scope length %u enterprise value: %u\n", 
				i, id, length, Get_val32(DataPtr));
		} else {
			dbg_printf(" [%i] Enterprise: 0, scope id: %u, scope length %u\n", i, id, length);
		}

		offset += length;
	}

	for ( ;i<field_count; i++ ) {
		uint32_t enterprise_value;
		uint16_t id, length;
		int Enterprise;

		UNUSED(enterprise_value);
		id 	   = Get_val16(DataPtr); DataPtr += 2;
		length = Get_val16(DataPtr); DataPtr += 2;
		size_left -= 4;
		Enterprise = id & 0x8000 ? 1 : 0;
		if ( Enterprise ) {
			size_required += 4;
			if ( size_left < 4 ) {
				LogError("Process_ipfix: [%u] option template length error: size left %u too", 
					exporter->info.id, size_left);
				dbg_printf("option template length error: size left %u too small\n", size_left);
				return;
			}
			enterprise_value = Get_val32(DataPtr);
			DataPtr += 4;
			size_left -= 4;
			dbg_printf(" [%i] Enterprise: 1, option id: %u, option length %u enterprise value: %u\n", 
				i, id, length, enterprise_value);
		} else {
			dbg_printf(" [%i] Enterprise: 0, option id: %u, option length %u\n", i, id, length);
		}

		switch (id) {
			case IPFIX_samplingInterval:		// legacy #34
			case IPFIX_samplingPacketInterval:	// #305
				if ( length == 4 ) {
					offset_std_sampler_interval = offset;
					found_std_sampling++;
					dbg_printf("	4 byte sampling interval option at offset: %u\n", offset);
				} else {
					LogError("Process_ipfix: [%u] option template error: sampling option lenth != 4 bytes: %u", 
						exporter->info.id, length);
				}
				break;
			case IPFIX_samplingAlgorithm:	// legacy #35
			case IPFIX_selectorAlgorithm:	// #304
				if ( length == 1 ) {
					offset_std_sampler_algorithm = offset;
					dbg_printf("	1 byte sampling algorithm option at offset: %u\n", offset);
					found_std_sampling++;
				} else {
					LogError("Process_ipfix: [%u] option template error: algorithm option lenth != 1 byte: %u", 
						exporter->info.id, length);
				}
				break;
		}

		offset += length;
	}

	if ( offset_std_sampler_interval ) {
        dbg_printf("[%u] Std sampling interval found. offset: %u\n", 
			exporter->info.id, offset_std_sampler_interval);
		if ( offset_std_sampler_algorithm )
        	dbg_printf("[%u] Std sampling algorithm found. offset: %u\n", 
			exporter->info.id, offset_std_sampler_algorithm);
        InsertStdSamplerOffset(fs, id, offset_std_sampler_interval, offset_std_sampler_algorithm);
		dbg_printf("\n");
	}

	processed_records++;

} // End of Process_ipfix_option_templates

Project: nfdump

static void Process_ipfix_templates(exporter_ipfix_domain_t *exporter, void *flowset_header, uint32_t size_left, FlowSource_t *fs) {
ipfix_template_record_t *ipfix_template_record;
void *DataPtr;
uint32_t count;

	size_left 	   -= 4;	// subtract message header
	DataPtr = flowset_header + 4;

	ipfix_template_record = (ipfix_template_record_t *)DataPtr;

	count = ntohs(ipfix_template_record->FieldCount);

	if ( count == 0 ) {
		Process_ipfix_template_withdraw(exporter, DataPtr, size_left, fs);
	} else {
		Process_ipfix_template_add(exporter, DataPtr, size_left, fs);
	}

} // End of Process_ipfix_templates

Project: nfdump
File: ipfix.c

static void PushSequence(input_translation_t *table, uint16_t Type, uint32_t *offset, void *stack) {
uint32_t i = table->number_of_sequences;
uint32_t index = cache.lookup_info[Type].index;

	if ( !CheckSequenceMap(table) )
		return;

	table->sequence[i].skip_count = 0;
	table->sequence[i].type = Type;
	if ( cache.lookup_info[Type].found ) {
			table->sequence[i].id = ipfix_element_map[index].sequence;
			table->sequence[i].output_offset = offset ? *offset : 0;
			table->sequence[i].stack = stack;
			table->sequence[i].input_length = cache.lookup_info[Type].length;
	} else {
			table->sequence[i].id = ipfix_element_map[index].zero_sequence;
			table->sequence[i].output_offset = offset ? *offset : 0;
			table->sequence[i].stack = NULL;
	}
	dbg_printf("Push: sequence: %u, Type: %u, in length: %u, out length: %u, id: %u, out offset: %u\n",
		i, Type, ipfix_element_map[index].length, ipfix_element_map[index].out_length, 
		table->sequence[i].id, table->sequence[i].output_offset);
	table->number_of_sequences++;
	if ( offset ) 
		(*offset) += ipfix_element_map[index].out_length;

} // End of PushSequence

Project: nfdump

static input_translation_t *add_translation_table(exporter_ipfix_domain_t *exporter, uint16_t id) {
input_translation_t **table;

	table = &(exporter->input_translation_table);
	while ( *table ) {
		table = &((*table)->next);
	}

	*table = calloc(1, sizeof(input_translation_t));
	if ( !(*table) ) {
			LogError("Process_ipfix: Panic! calloc() %s line %d: %s", __FILE__, __LINE__, strerror (errno));
			return NULL;
	}
	(*table)->max_number_of_sequences = 0;
	(*table)->number_of_sequences 	  = 0;
	(*table)->sequence = NULL;
	(*table)->id   	   = id;
	(*table)->next	   = NULL;

	dbg_printf("[%u] Get new translation table %u\n", exporter->info.id, id);

	return *table;

} // End of add_translation_table

Project: nfdump

static int compact_input_order(void) {
int i;

	dbg_printf("\nCompacting element input order: %u elements\n", cache.input_count);
	for ( i=0; i< cache.input_count; i++ ) {
		dbg_printf("%i: type: %u, length: %u\n", 
			i, cache.input_order[i].type, cache.input_order[i].length);
		
		if ( (cache.input_order[i].type == SKIP_ELEMENT) && (cache.input_order[i].length == DYN_FIELD_LENGTH) ) {
			dbg_printf("Dynamic length field: %u\n", cache.input_order[i].type);
			continue;
		}
		while ( (i+1) < cache.input_count &&
			(cache.input_order[i].type == SKIP_ELEMENT) && (cache.input_order[i].length != DYN_FIELD_LENGTH) &&
			(cache.input_order[i+1].type == SKIP_ELEMENT) && (cache.input_order[i+1].length != DYN_FIELD_LENGTH)) {
				int j;
				dbg_printf("%i: type: %u, length: %u\n", 
					i+1, cache.input_order[i+1].type, cache.input_order[i+1].length);
				dbg_printf("Merge order %u and %u\n", i, i+1);
				cache.input_order[i].type = SKIP_ELEMENT;
				cache.input_order[i].length += cache.input_order[i+1].length;
		
				for ( j=i+1; (j+1)<cache.input_count; j++) {
					cache.input_order[j] = cache.input_order[j+1];
				}
				cache.input_count--;
		}
	}

#ifdef DEVEL
	printf("\nCompacted input order table: count: %u\n", cache.input_count);
	for ( i=0; i< cache.input_count; i++ ) {
		dbg_printf("%i: Type: %u, Length: %u\n", 
			i, cache.input_order[i].type, cache.input_order[i].length);
	}
	printf("\n");
#endif

	for ( i=0; i< cache.input_count; i++ ) {
		if ( cache.input_order[i].type != SKIP_ELEMENT ) 
			return 1;
	}
	return 0;

} // End of compact_input_order

Project: nfdump

static void remove_all_translation_tables(exporter_ipfix_domain_t *exporter) {
input_translation_t *table, *next;

	LogInfo("Process_ipfix: Withdraw all templates from observation domain %u\n", 
		exporter->info.id);

	table = exporter->input_translation_table;
	while ( table ) {
		next = table->next;

		dbg_printf("\n[%u] Withdraw template ID: %u\n", exporter->info.id, table->id);

		free(table->sequence);
		free(table->extension_info.map);
		free(table);

		table = next;
	}

	exporter->input_translation_table = NULL;
	exporter->current_table = NULL;

} // End of remove_all_translation_tables

Project: nfdump

static void remove_translation_table(FlowSource_t *fs, exporter_ipfix_domain_t *exporter, uint16_t id) {
input_translation_t *table, *parent;

	LogInfo("Process_ipfix: [%u] Withdraw template id: %i", 
			exporter->info.id, id);

	parent = NULL;
	table = exporter->input_translation_table;
	while ( table && ( table->id != id ) ) {
		parent = table;
		table = table->next;
	}

	if ( table == NULL ) {
		LogError("Process_ipfix: [%u] Withdraw template id: %i. translation table not found", 
				exporter->info.id, id);
		return;
	}

	dbg_printf("\n[%u] Withdraw template ID: %u\n", exporter->info.id, table->id);

	if (exporter->current_table == table)
		exporter->current_table = NULL;

	if ( parent ) {
		parent->next = table->next;
	} else {
		exporter->input_translation_table = NULL;
	}

	RemoveExtensionMap(fs, table->extension_info.map);
	free(table->sequence);
	free(table->extension_info.map);
	free(table);

} // End of remove_translation_table

Project: nfdump

static int reorder_sequencer(input_translation_t *table) {
int i, n;
sequence_map_t *sequence = table->sequence;

#ifdef DEVEL
	printf("\nReorder Sequencer. Sequence steps: %u\n", table->number_of_sequences);
	for ( i=0; i<table->number_of_sequences; i++ ) {
		printf("Order: %i, Sequence: %u, Type: %u, Input length: %u, Output offset: %u, Skip Count: %u\n",
			i, sequence[i].id, sequence[i].type, sequence[i].input_length, 
			sequence[i].output_offset, sequence[i].skip_count);
	}
#endif

	n = 0;	// index into sequencer table
	for ( i=0; i<cache.input_count; i++ ) {
		if ( cache.input_order[i].type == SKIP_ELEMENT ) {
			if ( cache.input_order[i].length == DYN_FIELD_LENGTH || n == 0 ) {
				int j;

				if ( !CheckSequenceMap(table) )
					return 0;

				for ( j=table->number_of_sequences-1; j>=n; j-- ) {
					sequence[j+1] = sequence[j];
				}

				if ( cache.input_order[i].length == DYN_FIELD_LENGTH ) {
					sequence[n].id = dyn_skip;
					sequence[n].skip_count = 0;
				} else {
					sequence[n].id = nop;
					sequence[n].skip_count = cache.input_order[i].length;
				}
				sequence[n].type = SKIP_ELEMENT;
				sequence[n].input_length = 0;
				sequence[n].stack = NULL;
				table->number_of_sequences++;
				dbg_printf("Insert skip sequence in slot: %u, skip count: %u, dyn: %u\n", 
					n, sequence[n].skip_count, cache.input_order[i].length == DYN_FIELD_LENGTH ? 1 : 0);
			} else {
				sequence[n-1].skip_count += cache.input_order[i].length;
				dbg_printf("Merge skip count: %u into previous sequence: %u\n", cache.input_order[i].length, n-1);
				continue;
			}
		} else {
			if ( sequence[n].type != cache.input_order[i].type ) {
				sequence_map_t _s;
				int j = n+1;

				while ( sequence[j].type != cache.input_order[i].type && j < table->number_of_sequences )
					j++;

				if ( j == table->number_of_sequences ) {
					if ( n == 0 ) {
						return 0;
					} else {
						sequence[n-1].skip_count += cache.input_order[i].length;
						dbg_printf("Merge skip count: %u into previous sequence: %u\n", cache.input_order[i].length, n-1);
						continue;
					}
					return 0;
				}
				_s = sequence[n];
				sequence[n] = sequence[j];
				sequence[j] = _s;
				dbg_printf("Swap slots %u <-> %u\n", n, j);
			} else {
				dbg_printf("In order slot %u\n", n);
			}
		}
		n++;
	}

#ifdef DEVEL
	printf("\nReordered Sequencer. Sequence steps: %u\n", table->number_of_sequences);
	for ( int i=0; i<table->number_of_sequences; i++ ) {
		printf("Order: %i, Sequence: %u, Type: %u, Input length: %u, Output offset: %u, Skip Count: %u\n",
			i, sequence[i].id, sequence[i].type, sequence[i].input_length, 
			sequence[i].output_offset, sequence[i].skip_count);
	}
	printf("\n");
#endif

	return 1;

} // End of reorder_sequencer

Project: nfdump

static input_translation_t *setup_translation_table (exporter_ipfix_domain_t *exporter, uint16_t id) {
input_translation_t *table;
extension_map_t 	*extension_map;
uint32_t			i, ipv6, offset, next_extension;
size_t				size_required;

	ipv6 = 0;

	table = GetTranslationTable(exporter, id);
	if ( !table ) {
		LogInfo("Process_ipfix: [%u] Add template %u", exporter->info.id, id);
		table = add_translation_table(exporter, id);
		if ( !table ) {
			return NULL;
		}
		size_required = Max_num_extensions * sizeof(uint16_t) + sizeof(extension_map_t);
		size_required = (size_required + 3) &~(size_t)3;
		extension_map = malloc(size_required);
		if ( !extension_map ) {
			LogError("Process_ipfix: Panic! malloc() error in %s line %d: %s", __FILE__, __LINE__, strerror (errno));
			return  NULL;
		}
		extension_map->type 	   = ExtensionMapType;
		extension_map->size 	   = sizeof(extension_map_t);
		extension_map->map_id 	   = INIT_ID;
		extension_map->extension_size = 0;

		table->extension_info.map 	 = extension_map;
		table->extension_map_changed = 1;
		table->number_of_sequences 	 = 0;
 	} else {
		extension_map = table->extension_info.map;

		extension_map->size 	   	  = sizeof(extension_map_t);
		extension_map->extension_size = 0;
		free((void *)table->sequence);

		dbg_printf("[%u] Refresh template %u\n", exporter->info.id, id);
	}
	table->sequence = calloc(cache.max_ipfix_elements, sizeof(sequence_map_t));
	if ( !table->sequence ) {
		LogError("Process_ipfix: Panic! malloc() error in %s line %d: %s", __FILE__, __LINE__, strerror (errno));
		return  NULL;
	}
	table->number_of_sequences = 0;
	table->max_number_of_sequences = cache.max_ipfix_elements;

	table->updated  	= time(NULL);
	table->flags			= 0;
	SetFlag(table->flags, FLAG_PKG_64);
	SetFlag(table->flags, FLAG_BYTES_64);
	table->delta_time		= 0;
	table->icmpTypeCodeIPv4	= 0;
	table->router_ip_offset = 0;
	table->received_offset  = 0;

	dbg_printf("[%u] Build sequence table %u\n", exporter->info.id, id);

	table->id 			= id;

	/* 
	 * common data block: The common record is expected in the output stream. If not available
	 * in the template, fill values with 0
	 */

	offset = BYTE_OFFSET_first;
	if ( cache.lookup_info[IPFIX_flowStartDeltaMicroseconds].found ) {
		PushSequence( table, IPFIX_flowStartDeltaMicroseconds, NULL, &table->flow_start);
		PushSequence( table, IPFIX_flowEndDeltaMicroseconds, NULL, &table->flow_end);
		offset = BYTE_OFFSET_first + 8;
		table->delta_time = 1;
		dbg_printf("Time stamp: flow start/end delta microseconds: %u/%u\n",
			IPFIX_flowStartDeltaMicroseconds, IPFIX_flowEndDeltaMicroseconds);
	} else if ( cache.lookup_info[IPFIX_flowStartMilliseconds].found ) {
		PushSequence( table, IPFIX_flowStartMilliseconds, NULL, &table->flow_start);
		PushSequence( table, IPFIX_flowEndMilliseconds, NULL, &table->flow_end);
		offset = BYTE_OFFSET_first + 8;
		dbg_printf("Time stamp: flow start/end absolute milliseconds: %u/%u\n", 
			IPFIX_flowStartMilliseconds, IPFIX_flowEndMilliseconds);
	} else if ( cache.lookup_info[IPFIX_flowStartSysUpTime].found ) {
		PushSequence( table, IPFIX_flowStartSysUpTime, NULL, &table->flow_start);
		PushSequence( table, IPFIX_flowEndSysUpTime, NULL, &table->flow_end);
		offset = BYTE_OFFSET_first + 8;
		dbg_printf("Time stamp: flow start/end relative milliseconds: %u/%u\n", 
			IPFIX_flowStartSysUpTime, IPFIX_flowEndSysUpTime);
	} else if ( cache.lookup_info[IPFIX_flowStartSeconds].found ) {
		PushSequence( table, IPFIX_flowStartSeconds, NULL, &table->flow_start);
		PushSequence( table, IPFIX_flowEndSeconds, NULL, &table->flow_end);
		offset = BYTE_OFFSET_first + 8;
		dbg_printf("Time stamp: flow start/end absolute seconds: %u/%u\n", 
			IPFIX_flowStartSeconds, IPFIX_flowEndSeconds);
	}else {
		dbg_printf("Time stamp: No known format found\n");
		offset = BYTE_OFFSET_first + 8;
	}
	PushSequence( table, IPFIX_forwardingStatus, &offset, NULL);
	PushSequence( table, IPFIX_tcpControlBits, &offset, NULL);
	PushSequence( table, IPFIX_protocolIdentifier, &offset, NULL);
	PushSequence( table, IPFIX_ipClassOfService, &offset, NULL);

	PushSequence( table, IPFIX_SourceTransportPort, &offset, NULL);
	PushSequence( table, IPFIX_DestinationTransportPort, &offset, NULL);

	offset += 4;

	/* IP address record
	 * This record is expected in the output stream. If not available
	 * in the template, assume empty v4 address.
	 */
	if ( cache.lookup_info[IPFIX_SourceIPv4Address].found ) {
		PushSequence( table, IPFIX_SourceIPv4Address, &offset, NULL);
		PushSequence( table, IPFIX_DestinationIPv4Address, &offset, NULL);
	} else if ( cache.lookup_info[IPFIX_SourceIPv6Address].found ) {
		PushSequence( table, IPFIX_SourceIPv6Address, &offset, NULL);
		PushSequence( table, IPFIX_DestinationIPv6Address, &offset, NULL);
		SetFlag(table->flags, FLAG_IPV6_ADDR);
		ipv6 = 1;
	} else {
		PushSequence( table, IPFIX_SourceIPv4Address, &offset, NULL);
		PushSequence( table, IPFIX_DestinationIPv4Address, &offset, NULL);
	}

	if ( cache.lookup_info[IPFIX_packetTotalCount].found )
		PushSequence( table, IPFIX_packetTotalCount, &offset, &table->packets);
	else
		PushSequence( table, IPFIX_packetDeltaCount, &offset, &table->packets);
	SetFlag(table->flags, FLAG_PKG_64);

	if ( cache.lookup_info[IPFIX_octetTotalCount].found )
		PushSequence( table, IPFIX_octetTotalCount, &offset, &table->bytes);
	else
		PushSequence( table, IPFIX_octetDeltaCount, &offset, &table->bytes);
	SetFlag(table->flags, FLAG_BYTES_64);


	next_extension = 0;
	for (i=4; extension_descriptor[i].id; i++ ) {
		uint32_t map_index = i;

		if ( cache.common_extensions[i] == 0 )
			continue;

		switch(i) {
			case EX_IO_SNMP_2:
				PushSequence( table, IPFIX_ingressInterface, &offset, NULL);
				PushSequence( table, IPFIX_egressInterface, &offset, NULL);
				break;
			case EX_IO_SNMP_4:
				PushSequence( table, IPFIX_ingressInterface, &offset, NULL);
				PushSequence( table, IPFIX_egressInterface, &offset, NULL);
				break;
			case EX_AS_2:
				PushSequence( table, IPFIX_bgpSourceAsNumber, &offset, NULL);
				PushSequence( table, IPFIX_bgpDestinationAsNumber, &offset, NULL);
				break;
			case EX_AS_4:
				PushSequence( table, IPFIX_bgpSourceAsNumber, &offset, NULL);
				PushSequence( table, IPFIX_bgpDestinationAsNumber, &offset, NULL);
				break;
			case EX_MULIPLE:
				PushSequence( table, IPFIX_postIpClassOfService, &offset, NULL);
				PushSequence( table, IPFIX_flowDirection, &offset, NULL);
				if ( ipv6 ) {
					PushSequence( table, IPFIX_SourceIPv6PrefixLength, &offset, NULL);
					PushSequence( table, IPFIX_DestinationIPv6PrefixLength, &offset, NULL);
				} else {
					PushSequence( table, IPFIX_SourceIPv4PrefixLength, &offset, NULL);
					PushSequence( table, IPFIX_DestinationIPv4PrefixLength, &offset, NULL);
				}
				break;
			case EX_NEXT_HOP_v4:
				PushSequence( table, IPFIX_ipNextHopIPv4Address, &offset, NULL);
				break;
			case EX_NEXT_HOP_v6:
				PushSequence( table, IPFIX_ipNextHopIPv6Address, &offset, NULL);
				SetFlag(table->flags, FLAG_IPV6_NH);
				break;
			case EX_NEXT_HOP_BGP_v4:
				PushSequence( table, IPFIX_bgpNextHopIPv4Address, &offset, NULL);
				break;
			case EX_NEXT_HOP_BGP_v6:
				PushSequence( table, IPFIX_bgpNextHopIPv6Address, &offset, NULL);
				SetFlag(table->flags, FLAG_IPV6_NHB);
				break;
			case EX_VLAN:
				PushSequence( table, IPFIX_vlanId, &offset, NULL);
				PushSequence( table, IPFIX_postVlanId, &offset, NULL);
				break;
			case EX_OUT_PKG_4:
				PushSequence( table, IPFIX_postPacketDeltaCount, &offset, NULL);
				break;
			case EX_OUT_PKG_8:
				PushSequence( table, IPFIX_postPacketDeltaCount, &offset, NULL);
				break;
			case EX_OUT_BYTES_4:
				PushSequence( table, IPFIX_postOctetDeltaCount, &offset, NULL);
				break;
			case EX_OUT_BYTES_8:
				PushSequence( table, IPFIX_postOctetDeltaCount, &offset, NULL);
				break;
			case EX_AGGR_FLOWS_8:
				break;
			case EX_MAC_1:
				PushSequence( table, IPFIX_SourceMacAddress, &offset, NULL);
				PushSequence( table, IPFIX_postDestinationMacAddress, &offset, NULL);
				break;
			case EX_MAC_2:
				PushSequence( table, IPFIX_DestinationMacAddress, &offset, NULL);
				PushSequence( table, IPFIX_postSourceMacAddress, &offset, NULL);
				break;
			case EX_MPLS:
				PushSequence( table, IPFIX_mplsTopLabelStackSection, &offset, NULL);
				PushSequence( table, IPFIX_mplsLabelStackSection2, &offset, NULL);
				PushSequence( table, IPFIX_mplsLabelStackSection3, &offset, NULL);
				PushSequence( table, IPFIX_mplsLabelStackSection4, &offset, NULL);
				PushSequence( table, IPFIX_mplsLabelStackSection5, &offset, NULL);
				PushSequence( table, IPFIX_mplsLabelStackSection6, &offset, NULL);
				PushSequence( table, IPFIX_mplsLabelStackSection7, &offset, NULL);
				PushSequence( table, IPFIX_mplsLabelStackSection8, &offset, NULL);
				PushSequence( table, IPFIX_mplsLabelStackSection9, &offset, NULL);
				PushSequence( table, IPFIX_mplsLabelStackSection10, &offset, NULL);
				break;
			case EX_ROUTER_IP_v4:
			case EX_ROUTER_IP_v6:
				if ( exporter->info.sa_family == PF_INET6 ) {
					table->router_ip_offset = offset;
					dbg_printf("Router IPv6: offset: %u, olen: %u\n", offset, 16 );
					offset			 	   += 16;
					SetFlag(table->flags, FLAG_IPV6_EXP);
					map_index = EX_ROUTER_IP_v6;
				} else {
					table->router_ip_offset = offset;
					dbg_printf("Router IPv4: offset: %u, olen: %u\n", offset, 4 );
					offset				   += 4;
					ClearFlag(table->flags, FLAG_IPV6_EXP);
					map_index = EX_ROUTER_IP_v4;
				}
				break;
			case EX_ROUTER_ID:
				break;
			case EX_RECEIVED:
				table->received_offset = offset;
				dbg_printf("Received offset: %u\n", offset);
				offset				   += 8;
				break;

		}
		extension_map->size += sizeof(uint16_t);
		extension_map->extension_size += extension_descriptor[map_index].size;


		if ( extension_map->ex_id[next_extension] != map_index ) {
			extension_map->ex_id[next_extension] = map_index;
			table->extension_map_changed = 1;

		}
		next_extension++;

	}
	extension_map->ex_id[next_extension++] = 0;

	if ( extension_map->size & 0x3 ) {
		extension_map->ex_id[next_extension] = 0;
		extension_map->size = ( extension_map->size + 3 ) &~ 0x3;
	}
 
	table->output_record_size = offset;

	if ( cache.lookup_info[IPFIX_icmpTypeCodeIPv4].found && cache.lookup_info[IPFIX_icmpTypeCodeIPv4].length == 2 ) {
		PushSequence( table, IPFIX_icmpTypeCodeIPv4, NULL, &table->icmpTypeCodeIPv4);
	}

#ifdef DEVEL
	if ( table->extension_map_changed ) {
		printf("Extension Map id=%u changed!\n", extension_map->map_id);
	} else {
		printf("[%u] template %u unchanged\n", exporter->info.id, id);
	}

	printf("Process_ipfix: Check extension map: id: %d, size: %u, extension_size: %u\n", 
		extension_map->map_id, extension_map->size, extension_map->extension_size);
	{ int i;
	for (i=0; i<table->number_of_sequences; i++ ) {
		printf("Sequence %i: id: %u, Type: %u, Length: %u, Output offset: %u, stack: %llu\n",
			i, table->sequence[i].id, table->sequence[i].type, table->sequence[i].input_length, 
			table->sequence[i].output_offset, (unsigned long long)table->sequence[i].stack);
	}
	printf("Flags: 0x%x output record size: %u\n", table->flags, table->output_record_size); 
	}
	PrintExtensionMap(extension_map);
#endif

	return table;

} // End of setup_translation_table