diff --git a/src/Conn.cc b/src/Conn.cc index 8ef756b134..fbc53a9d9a 100644 --- a/src/Conn.cc +++ b/src/Conn.cc @@ -216,56 +216,6 @@ Connection::~Connection() --external_connections; } -uint64 Connection::uid_counter = 0; -uint64 Connection::uid_instance = 0; - -uint64 Connection::CalculateNextUID() - { - if ( uid_instance == 0 ) - { - // This is the first time we need a UID. - - if ( ! have_random_seed() ) - { - // If we don't need deterministic output (as - // indicated by a set seed), we calculate the - // instance ID by hashing something likely to be - // globally unique. - struct { - char hostname[128]; - struct timeval time; - pid_t pid; - int rnd; - } unique; - - gethostname(unique.hostname, 128); - unique.hostname[sizeof(unique.hostname)-1] = '\0'; - gettimeofday(&unique.time, 0); - unique.pid = getpid(); - unique.rnd = bro_random(); - - uid_instance = HashKey::HashBytes(&unique, sizeof(unique)); - ++uid_instance; // Now it's larger than zero. - } - - else - // Generate determistic UIDs. - uid_instance = 1; - } - - // Now calculate the unique ID for this connection. - struct { - uint64 counter; - hash_t instance; - } key; - - key.counter = ++uid_counter; - key.instance = uid_instance; - - uint64_t h = HashKey::HashBytes(&key, sizeof(key)); - return h; - } - void Connection::Done() { finished = 1; @@ -417,7 +367,7 @@ RecordVal* Connection::BuildConnVal() conn_val->Assign(8, new StringVal("")); // history if ( ! uid ) - uid = CalculateNextUID(); + uid = calculate_unique_id(); char tmp[20]; conn_val->Assign(9, new StringVal(uitoa_n(uid, tmp, sizeof(tmp), 62))); diff --git a/src/Conn.h b/src/Conn.h index 8a178d783a..8c962b9bb7 100644 --- a/src/Conn.h +++ b/src/Conn.h @@ -303,8 +303,6 @@ public: void SetUID(uint64 arg_uid) { uid = arg_uid; } - static uint64 CalculateNextUID(); - protected: Connection() { persistent = 0; } @@ -363,9 +361,6 @@ protected: PIA* primary_PIA; uint64 uid; // Globally unique connection ID. - - static uint64 uid_counter; // Counter for uids. - static uint64 uid_instance; // Instance ID, computed once. }; class ConnectionTimer : public Timer { diff --git a/src/ConnCompressor.cc b/src/ConnCompressor.cc index e6428aeebe..7c82b12af0 100644 --- a/src/ConnCompressor.cc +++ b/src/ConnCompressor.cc @@ -620,7 +620,7 @@ void ConnCompressor::PktHdrToPendingConn(double time, const HashKey* key, c->FIN = (tp->th_flags & TH_FIN) != 0; c->RST = (tp->th_flags & TH_RST) != 0; c->ACK = (tp->th_flags & TH_ACK) != 0; - c->uid = Connection::CalculateNextUID(); + c->uid = calculate_unique_id(); c->num_bytes_ip = ip->TotalLen(); c->num_pkts = 1; c->invalid = 0; diff --git a/src/bro.bif b/src/bro.bif index 7f83e16784..a330ea77e8 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -3349,6 +3349,12 @@ function bro_has_ipv6%(%) : bool #endif %} +function unique_id%(prefix: string%) : bool + %{ + char tmp[20]; + uint64 uid = calculate_unique_id(); + return new StringVal(uitoa_n(uid, tmp, sizeof(tmp), 62, prefix->CheckString())); + %} %%{ #include diff --git a/src/util.cc b/src/util.cc index 3d69c981be..f0c38009af 100644 --- a/src/util.cc +++ b/src/util.cc @@ -344,15 +344,27 @@ template int atoi_n(int len, const char* s, const char** end, int base, template int atoi_n(int len, const char* s, const char** end, int base, int& result); template int atoi_n(int len, const char* s, const char** end, int base, int64_t& result); -char* uitoa_n(uint64 value, char* str, int n, int base) +char* uitoa_n(uint64 value, char* str, int n, int base, const char* prefix) { static char dig[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + assert(n); + int i = 0; uint64 v; char* p, *q; char c; + if ( prefix ) + { + strncpy(str, prefix, n); + str[n-1] = '\0'; + i += strlen(prefix); + } + + if ( i >= n ) + return str; + v = value; do { @@ -1122,6 +1134,56 @@ int time_compare(struct timeval* tv_a, struct timeval* tv_b) return tv_a->tv_sec - tv_b->tv_sec; } +static uint64 uid_counter; // Counter for unique IDs. +static uint64 uid_instance; // Instance ID, computed once. + +uint64 calculate_unique_id() + { + if ( uid_instance == 0 ) + { + // This is the first time we need a UID. + + if ( ! have_random_seed() ) + { + // If we don't need deterministic output (as + // indicated by a set seed), we calculate the + // instance ID by hashing something likely to be + // globally unique. + struct { + char hostname[128]; + struct timeval time; + pid_t pid; + int rnd; + } unique; + + gethostname(unique.hostname, 128); + unique.hostname[sizeof(unique.hostname)-1] = '\0'; + gettimeofday(&unique.time, 0); + unique.pid = getpid(); + unique.rnd = bro_random(); + + uid_instance = HashKey::HashBytes(&unique, sizeof(unique)); + ++uid_instance; // Now it's larger than zero. + } + + else + // Generate determistic UIDs. + uid_instance = 1; + } + + // Now calculate the unique ID. + struct { + uint64 counter; + hash_t instance; + } key; + + key.counter = ++uid_counter; + key.instance = uid_instance; + + uint64_t h = HashKey::HashBytes(&key, sizeof(key)); + return h; + } + void out_of_memory(const char* where) { fprintf( stderr, "bro: out of memory in %s.\n", where ); diff --git a/src/util.h b/src/util.h index a288ed30c8..6aad1271af 100644 --- a/src/util.h +++ b/src/util.h @@ -111,7 +111,7 @@ extern char* strcasestr(const char* s, const char* find); #endif extern const char* strpbrk_n(size_t len, const char* s, const char* charset); template int atoi_n(int len, const char* s, const char** end, int base, T& result); -extern char* uitoa_n(uint64 value, char* str, int n, int base); +extern char* uitoa_n(uint64 value, char* str, int n, int base, const char* prefix=0); int strstr_n(const int big_len, const unsigned char* big, const int little_len, const unsigned char* little); extern int fputs(int len, const char* s, FILE* fp); @@ -233,6 +233,10 @@ extern struct timeval double_to_timeval(double t); // Return > 0 if tv_a > tv_b, 0 if equal, < 0 if tv_a < tv_b. 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 +// instances. +extern uint64 calculate_unique_id(); + // For now, don't use hash_maps - they're not fully portable. #if 0 // Use for hash_map's string keys. diff --git a/testing/btest/Baseline/bifs.unique_id-rnd/count b/testing/btest/Baseline/bifs.unique_id-rnd/count new file mode 100644 index 0000000000..1e8b314962 --- /dev/null +++ b/testing/btest/Baseline/bifs.unique_id-rnd/count @@ -0,0 +1 @@ +6 diff --git a/testing/btest/Baseline/bifs.unique_id/out b/testing/btest/Baseline/bifs.unique_id/out new file mode 100644 index 0000000000..f1275a52d4 --- /dev/null +++ b/testing/btest/Baseline/bifs.unique_id/out @@ -0,0 +1,3 @@ +A-UWkUyAuUGXf +B-56gKBmhBBB6 +C-50da4BEzauh diff --git a/testing/btest/bifs/unique_id-rnd.bro b/testing/btest/bifs/unique_id-rnd.bro new file mode 100644 index 0000000000..4ac41ff1b5 --- /dev/null +++ b/testing/btest/bifs/unique_id-rnd.bro @@ -0,0 +1,9 @@ +# +# @TEST-EXEC: BRO_SEED_FILE= bro %INPUT 2>/dev/null >out +# @TEST-EXEC: BRO_SEED_FILE= bro %INPUT 2>/dev/null >>out +# @TEST-EXEC: cat out | sort | uniq | wc -l >count +# @TEST-EXEC: btest-diff count + +print unique_id("A-"); +print unique_id("B-"); +print unique_id("C-"); diff --git a/testing/btest/bifs/unique_id.bro b/testing/btest/bifs/unique_id.bro new file mode 100644 index 0000000000..d421803aa0 --- /dev/null +++ b/testing/btest/bifs/unique_id.bro @@ -0,0 +1,7 @@ +# +# @TEST-EXEC: bro %INPUT >out +# @TEST-EXEC: btest-diff out + +print unique_id("A-"); +print unique_id("B-"); +print unique_id("C-");