Some working code. Adds UID pools classified by string. Just compiles

and runs; need to go back through and make sure this code is actually
doing what I want it to do.

Note: Added new function unique_id_from(pool: string, prefix: string)
that allows the user to explicitly specify a randomness pool to use when
generating unique IDs.
This commit is contained in:
Gilbert Clark gc355804@ohio.edu 2011-08-08 22:12:40 -07:00
parent f36310dc0e
commit 9322c063cc
10 changed files with 78 additions and 21 deletions

View file

@ -3414,10 +3414,16 @@ function bro_has_ipv6%(%) : bool
function unique_id%(prefix: string%) : string function unique_id%(prefix: string%) : string
%{ %{
char tmp[20]; char tmp[20];
uint64 uid = calculate_unique_id(); uint64 uid = calculate_unique_id(BRO_SCRIPT_UID_POOL);
return new StringVal(uitoa_n(uid, tmp, sizeof(tmp), 62, prefix->CheckString())); return new StringVal(uitoa_n(uid, tmp, sizeof(tmp), 62, prefix->CheckString()));
%} %}
function unique_id_from%(pool: string, prefix: string%) : string
%{
char tmp[20];
uint64 uid = calculate_unique_id(string((const char *)pool->Bytes(), pool->Len()));
return new StringVal(uitoa_n(uid, tmp, sizeof(tmp), 62, prefix->CheckString()));
%}
%%{ %%{
#include <openssl/x509.h> #include <openssl/x509.h>
#include <openssl/asn1.h> #include <openssl/asn1.h>

View file

@ -1206,15 +1206,30 @@ int time_compare(struct timeval* tv_a, struct timeval* tv_b)
return tv_a->tv_sec - tv_b->tv_sec; return tv_a->tv_sec - tv_b->tv_sec;
} }
static uint64 uid_counter; // Counter for unique IDs. struct BroUidEntry
static uint64 uid_instance; // Instance ID, computed once. {
uint64 instance;
uint64 counter;
BroUidEntry(const uint64 i)
: instance(i), counter(0) { }
};
static std::map<string, BroUidEntry> uid_pool;
static const std::string default_pool = string(BRO_DEFAULT_UID_POOL);
uint64 calculate_unique_id() uint64 calculate_unique_id()
{ {
if ( uid_instance == 0 ) return calculate_unique_id(default_pool);
{ }
// This is the first time we need a UID.
uint64 calculate_unique_id(const std::string& pool)
{
uint64 uid_instance = 0;
std::map<std::string, BroUidEntry>::iterator pool_iter = uid_pool.find(pool);
if ( pool_iter == uid_pool.end() )
{
// This is the first time we need a UID for this pool.
const size_t pool_sz = (pool.length() < 32) ? pool.length() : 32; //Only keep the first 32 characters of the pool name
if ( ! have_random_seed() ) if ( ! have_random_seed() )
{ {
// If we don't need deterministic output (as // If we don't need deterministic output (as
@ -1222,14 +1237,16 @@ uint64 calculate_unique_id()
// instance ID by hashing something likely to be // instance ID by hashing something likely to be
// globally unique. // globally unique.
struct { struct {
char hostname[128]; char hostname[96];
char pool[32];
struct timeval time; struct timeval time;
pid_t pid; pid_t pid;
int rnd; int rnd;
} unique; } unique;
memset(&unique, 0, sizeof(unique)); // Make valgrind happy. memset(&unique, 0, sizeof(unique)); // Make valgrind happy.
gethostname(unique.hostname, 128); gethostname(unique.hostname, 96);
memcpy(unique.pool, pool.c_str(), pool_sz);
unique.hostname[sizeof(unique.hostname)-1] = '\0'; unique.hostname[sizeof(unique.hostname)-1] = '\0';
gettimeofday(&unique.time, 0); gettimeofday(&unique.time, 0);
unique.pid = getpid(); unique.pid = getpid();
@ -1238,22 +1255,38 @@ uint64 calculate_unique_id()
uid_instance = HashKey::HashBytes(&unique, sizeof(unique)); uid_instance = HashKey::HashBytes(&unique, sizeof(unique));
++uid_instance; // Now it's larger than zero. ++uid_instance; // Now it's larger than zero.
} }
else else
// Generate determistic UIDs. {
uid_instance = 1; // Generate determistic UIDs for each individual pool
uid_instance = HashKey::HashBytes(pool.c_str(), strnlen(pool.c_str(), pool_sz));
}
// Guarantee no collisions (keep hashing until we get a unique instance)
bool found_collision = true;
while(found_collision)
{
found_collision = false;
for(pool_iter = uid_pool.begin(); pool_iter != uid_pool.end(); ++pool_iter)
{
if(pool_iter->second.instance == uid_instance)
{
found_collision = true;
uid_instance = HashKey::HashBytes(&uid_instance, sizeof(uid_instance));
}
}
}
// Our instance is unique. Huzzah.
uid_pool.insert(std::make_pair(pool, BroUidEntry(uid_instance)));
pool_iter = uid_pool.end();
} }
// Now calculate the unique ID. if(pool_iter == uid_pool.end())
struct { {
uint64 counter; pool_iter = uid_pool.find(pool);
hash_t instance; }
} key; assert(pool_iter != uid_pool.end()); // After all that work, wouldn't it be a shame...?
++(pool_iter->second.counter);
key.counter = ++uid_counter; uint64_t h = HashKey::HashBytes(&(pool_iter->second), sizeof(pool_iter->second));
key.instance = uid_instance;
uint64_t h = HashKey::HashBytes(&key, sizeof(key));
return h; return h;
} }

View file

@ -226,7 +226,10 @@ extern int time_compare(struct timeval* tv_a, struct timeval* tv_b);
// Returns an integer that's very likely to be unique, even across Bro // Returns an integer that's very likely to be unique, even across Bro
// instances. // instances.
#define BRO_DEFAULT_UID_POOL "bro"
#define BRO_SCRIPT_UID_POOL "bro script"
extern uint64 calculate_unique_id(); extern uint64 calculate_unique_id();
extern uint64 calculate_unique_id(const std::string& pool);
// For now, don't use hash_maps - they're not fully portable. // For now, don't use hash_maps - they're not fully portable.
#if 0 #if 0

View file

@ -7,3 +7,6 @@
print unique_id("A-"); print unique_id("A-");
print unique_id("B-"); print unique_id("B-");
print unique_id("C-"); print unique_id("C-");
print unique_id_from("alpha", "D-");
print unique_id_from("beta", "E-");
print unique_id_from("beta", "F-");

View file

@ -5,3 +5,6 @@
print unique_id("A-"); print unique_id("A-");
print unique_id("B-"); print unique_id("B-");
print unique_id("C-"); print unique_id("C-");
print unique_id_from("alpha", "D-");
print unique_id_from("beta", "E-");
print unique_id_from("beta", "F-");

View file

@ -1,4 +1,5 @@
[btest] [btest]
ProfileDir = profiles
TestDirs = doc bifs language core policy istate TestDirs = doc bifs language core policy istate
TmpDir = %(testbase)s/.tmp TmpDir = %(testbase)s/.tmp
BaselineDir = %(testbase)s/Baseline BaselineDir = %(testbase)s/Baseline

View file

@ -0,0 +1,2 @@
#!/usr/bin/env bash

View file

@ -0,0 +1,2 @@
#!/usr/bin/env bash

View file

@ -0,0 +1,2 @@
#!/usr/bin/env bash

View file

@ -0,0 +1,2 @@
#!/usr/bin/env bash