static void ExportExtensionMaps( int aggregate, int bidir, nffile_t *nffile, extension_map_list_t *extension_map_list ) { int map_id, opt_extensions, num_extensions, new_map_size, opt_align; extension_map_t *new_map; // no extension maps to export - nothing to do if ( extension_map_list->map_list == NULL ) return; new_map = NULL; for ( map_id = 0; map_id <= extension_map_list->max_used; map_id++ ) { extension_map_t *SourceMap = extension_map_list->slot[map_id]->map; int i, has_aggr_flows, has_out_bytes, has_out_packets, has_nat; // skip maps, never referenced #ifdef DEVEL printf("Process map id: %i\n", map_id); printf("Ref count: %i\n", extension_map_list->slot[map_id]->ref_count); #endif if ( extension_map_list->slot[map_id]->ref_count == 0 ) { #ifdef DEVEL printf("Ref count = 0 => Skip map\n"); #endif continue; } // parse Source map if it contains all required fields: // for aggregation EX_AGGR_FLOWS_4 or _8 is required // for bidir flows EX_OUT_PKG_4 or _8 and EX_OUT_BYTES_4 or_8 are required has_aggr_flows = 0; has_out_bytes = 0; has_out_packets = 0; // parse map for older NEL nat extension has_nat = 0; num_extensions = 0; i = 0; while ( SourceMap->ex_id[i] ) { switch (SourceMap->ex_id[i]) { case EX_AGGR_FLOWS_4: case EX_AGGR_FLOWS_8: has_aggr_flows = 1; break; case EX_OUT_BYTES_4: case EX_OUT_BYTES_8: has_out_bytes = 1; break; case EX_OUT_PKG_4: case EX_OUT_PKG_8: has_out_packets = 1; break; case EX_NEL_GLOBAL_IP_v4: // Map old nat extension to common NSEL extension SourceMap->ex_id[i] = EX_NSEL_XLATE_IP_v4; has_nat = 1; // default: nothing to do } i++; num_extensions++; } #ifdef DEVEL printf("map: num_extensions: %i, has_aggr_flows: %i, has_out_bytes: %i, has_out_packets: %i, has_nat: %i\n", num_extensions, has_aggr_flows, has_out_bytes, has_out_packets, has_nat); #endif // count missing extensions opt_extensions = 0; if ( aggregate && !has_aggr_flows ) opt_extensions++; if ( bidir && !has_out_bytes ) opt_extensions++; if ( bidir && !has_out_packets ) opt_extensions++; opt_extensions += has_nat; // calculate new map size new_map_size = sizeof(extension_map_t) + ( num_extensions + opt_extensions) * sizeof(uint16_t); #ifdef DEVEL printf("opt_extensions: %i, new_map_size: %i\n", opt_extensions,new_map_size ); PrintExtensionMap(SourceMap); #endif if ( opt_extensions ) { // align 32bits if (( new_map_size & 0x3 ) != 0 ) { new_map_size += 4 - ( new_map_size & 0x3 ); opt_align = 1; } else { opt_align = 0; } } else { // no missing elements in extension map - we can used the original one // and we are done #ifdef DEVEL printf("New map identical => use this map:\n"); PrintExtensionMap(SourceMap); #endif // Flush the map to disk AppendToBuffer(nffile, (void *)SourceMap, SourceMap->size); continue; } #ifdef DEVEL printf("Create new map:\n"); #endif // new map is different - create the new map new_map = (extension_map_t *)malloc((ssize_t)new_map_size); if ( !new_map ) { LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) ); exit(255); } // Panic check - should never happen, but we are going to copy memory if ( new_map_size < SourceMap->size ) { LogError("PANIC! new_map_size(%i) < SourceMap->size(%i) in %s line %d\n", new_map_size, SourceMap->size, __FILE__, __LINE__); exit(255); } // copy existing map memcpy((void *)new_map, (void *)SourceMap, SourceMap->size); new_map->size = new_map_size; // add the missing extensions to the output map // skip to end of current map while ( new_map->ex_id[i] ) i++; if ( has_nat ) { new_map->ex_id[i++] = EX_NSEL_XLATE_PORTS; new_map->extension_size += extension_descriptor[EX_NSEL_XLATE_PORTS].size; } // add missing map elements if ( aggregate && !has_aggr_flows ) { new_map->ex_id[i++] = EX_AGGR_FLOWS_4; new_map->extension_size += extension_descriptor[EX_AGGR_FLOWS_4].size; } if ( bidir && !has_out_bytes ) { new_map->ex_id[i++] = EX_OUT_BYTES_8; new_map->extension_size += extension_descriptor[EX_OUT_BYTES_8].size; } if ( bidir && !has_out_packets ) { new_map->ex_id[i++] = EX_OUT_PKG_8; new_map->extension_size += extension_descriptor[EX_OUT_PKG_8].size; } // end of map tag new_map->ex_id[i++] = 0; if ( opt_align ) new_map->ex_id[i] = 0; #ifdef DEVEL PrintExtensionMap(new_map); #endif free(extension_map_list->slot[map_id]->map); extension_map_list->slot[map_id]->map = new_map; // Flush the map to disk AppendToBuffer(nffile, (void *)new_map, new_map->size); } } // End of ExportExtensionMaps
int Insert_Extension_Map (extension_map_list_t * extension_map_list, extension_map_t * map) { uint32_t next_free = extension_map_list->next_free; uint16_t map_id; map_id = map->map_id == INIT_ID ? 0 : map->map_id & EXTENSION_MAP_MASK; map->map_id = map_id; dbg_printf ("Insert Extension Map:\n"); #ifdef DEVEL PrintExtensionMap (map); #endif // is this slot free if (extension_map_list->slot[map_id]) { int i, map_found; dbg_printf ("Map %d already exists\n", map_id); // no - check if same map already in slot if (extension_map_list->slot[map_id]->map->size == map->size) { // existing map and new map have the same size dbg_printf ("New map same size:\n"); // we must compare the maps i = 0; while (extension_map_list->slot[map_id]->map->ex_id[i] && (extension_map_list->slot[map_id]->map->ex_id[i] == map->ex_id[i])) i++; // if last entry == 0 => last map entry => maps are the same if (extension_map_list->slot[map_id]->map->ex_id[i] == 0) { dbg_printf ("Same map => nothing to do\n"); // same map return 0; } dbg_printf ("Different map => continue\n"); } dbg_printf ("Search for map in extension page\n"); map_found = -1; // new map is different but has same id - search for map in page list for (i = 0; i < next_free; i++) { int j; j = 0; if (extension_map_list->page[i]->map->size == map->size) { while (extension_map_list->page[i]->map->ex_id[j] && (extension_map_list->page[i]->map->ex_id[j] == map->ex_id[j])) j++; } if (extension_map_list->page[i]->map->ex_id[j] == 0) { dbg_printf ("Map found in page slot %i\n", i); map_found = i; } } if (map_found >= 0) { extension_info_t *tmp; dbg_printf ("Move map from page slot %i to slot %i\n", map_found, map_id); // exchange the two maps tmp = extension_map_list->slot[map_id]; extension_map_list->slot[map_id] = extension_map_list->page[map_found]; extension_map_list->slot[map_id]->map->map_id = map_id; extension_map_list->page[map_found] = tmp; extension_map_list->page[map_found]->map->map_id = map_found; return 1; } else { dbg_printf ("Map not found in extension page\n"); // map not found - move it to the extension page to a currently free slot if (next_free < MAX_EXTENSION_MAPS) { dbg_printf ("Move existing map from slot %d to page slot %d\n", map_id, next_free); extension_map_list->page[next_free] = extension_map_list->slot[map_id]; extension_map_list->page[next_free]->map->map_id = next_free; extension_map_list->slot[map_id] = NULL; // ready to fill new slot } else { fprintf (stderr, "Extension map list exhausted - too many extension maps ( > %d ) to process;\n", MAX_EXTENSION_MAPS); exit (255); } } } FixExtensionMap (map); // add new entry to slot extension_map_list->slot[map_id] = (extension_info_t *) calloc (1, sizeof (extension_info_t)); if (!extension_map_list->slot[map_id]) { fprintf (stderr, "calloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno)); exit (255); } extension_map_list->slot[map_id]->map = (extension_map_t *) malloc ((ssize_t) map->size); if (!extension_map_list->slot[map_id]->map) { fprintf (stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno)); exit (255); } memcpy ((void *) extension_map_list->slot[map->map_id]->map, (void *) map, map->size); extension_map_list->slot[map_id]->ref_count = 0; if (map_id > extension_map_list->max_used) { extension_map_list->max_used = map_id; } // Update next_free page slot, if it's used now while (extension_map_list->page[next_free] && (next_free < MAX_EXTENSION_MAPS)) next_free++; extension_map_list->next_free = next_free; // if all slots are exhausted next_free is now MAX_EXTENSION_MAPS. The next time an empty slot is needed, it will properly fail. dbg_printf ("Installed map in slot %d. Next free page slot: %d\n", map_id, next_free); //map changed return 1; } // End of Insert_Extension_Map
int main(int argc, char **argv) { struct ftio ftio; extension_info_t *extension_info; struct stat statbuf; uint32_t limitflows; int i, extended, printmap, ret, fd, compress;; char *ftfile, *wfile; /* init fterr */ fterr_setid(argv[0]); extended = 0; printmap = 0; limitflows = 0; ftfile = NULL; wfile = "-"; compress = NOT_COMPRESSED; while ((i = getopt(argc, argv, "jzEVc:hmr:w:?")) != -1) switch (i) { case 'h': /* help */ case '?': usage(argv[0]); exit (0); break; case 'V': printf("%s: Version: %s\n",argv[0], nfdump_version); exit(0); break; case 'E': extended = 1; break; case 'c': limitflows = atoi(optarg); if ( !limitflows ) { fprintf(stderr, "Option -c needs a number > 0\n"); exit(255); } break; case 'm': printmap = 1; break; case 'j': compress = LZO_COMPRESSED; break; case 'z': compress = BZ2_COMPRESSED; break; case 'r': ftfile = optarg; if ( (stat(ftfile, &statbuf) < 0 ) || !(statbuf.st_mode & S_IFREG) ) { fprintf(stderr, "No such file: '%s'\n", ftfile); exit(255); } break; case 'w': wfile = optarg; break; default: usage(argv[0]); exit (1); break; } /* switch */ // End while if (argc - optind) fterr_errx(1, "Extra arguments starting with %s.", argv[optind]); if ( ftfile ) { fd = open(ftfile, O_RDONLY, 0); if ( fd < 0 ) { fprintf(stderr, "Can't open file '%s': %s.", ftfile, strerror(errno)); exit(255); } } else { fd = 0; } /* read from fd */ if (ftio_init(&ftio, fd, FT_IO_FLAG_READ) < 0) fterr_errx(1, "ftio_init(): failed"); extension_info = GenExtensionMap(&ftio); if ( !extension_info ) exit(255); if ( printmap ) { PrintExtensionMap(extension_info->map); exit(255); } ret = flows2nfdump(&ftio, wfile, compress, extension_info, extended, limitflows); return ret; } // End of main