Add find_next_available_key function to prevent overwriting buckets

This commit is contained in:
onyinyang 2023-06-27 15:47:56 -04:00
parent 48cdb97a9f
commit 40f1e88a31
No known key found for this signature in database
GPG Key ID: 156A6435430C2036
2 changed files with 66 additions and 7 deletions

View File

@ -255,14 +255,20 @@ pub struct BridgeTable {
/// In some instances a single bridge may need to be added to a bucket
/// In that case, a spare bucket will be removed from the set of spare bridges. One
pub unallocated_bridges: Vec<BridgeLine>,
// To prevent issues with a counter for the hashmap keys, we keep a list of keys that
// no longer match any buckets that can be used before increasing the counter
pub recycleable_keys: Vec<u32>,
// We maintain a list of keys that have been blocked, as well as the date of their blocking
// so that they can be repurposed with new buckets eventually
pub blocked_keys: Vec<(u32, u32)>,
/// The date the buckets were last encrypted to make the encbucket.
/// The encbucket must be rebuilt each day so that the Bucket
/// Reachability credentials in the buckets can be refreshed.
pub date_last_enc: u32,
}
// Invariant: the lengths of the keys and buckets vectors are the same.
// The encbuckets vector only gets updated when encrypt_table is called.
// Invariant: the lengths of the keys and bucket hashmap are the same.
// The encbuckets hashmap only gets updated when encrypt_table is called.
impl BridgeTable {
/// Get the number of buckets in the bridge table
@ -270,6 +276,54 @@ impl BridgeTable {
self.buckets.len()
}
/// Get today's (real or simulated) date
fn today(&self) -> u32 {
// We will not encounter negative Julian dates (~6700 years ago)
// or ones larger than 32 bits
(time::OffsetDateTime::now_utc().date())
.to_julian_day()
.try_into()
.unwrap()
}
// Since buckets are moved around in the bridge_table, finding a lookup key that
// does not overwrite existing bridges could become an issue. We keep a list
// of recycleable lookup keys from buckets that have been removed and prioritize
// this list before increasing the counter
fn find_next_available_key(&mut self) -> u32 {
// First check if there are any blocked indexes that are old enough to be replaced
if !self.blocked_keys.is_empty()
&& self.blocked_keys.iter().any(|&x| x.1 > self.today() + 30)
//Perhaps 30 should be changed to a later/earlier time
{
let blocked_keys_clone = self.blocked_keys.clone();
// If so, separate them from the fresh blockages
let (expired, fresh): (Vec<(u32, u32)>, Vec<(u32, u32)>) = blocked_keys_clone
.into_iter()
.partition(|&x| x.1 > self.today() + 30);
for item in expired {
let new_item = item.0;
//and add them to the recyclable keys
self.recycleable_keys.push(new_item);
}
// update the blocked_keys vector to only include the fresh keys
self.blocked_keys = fresh
}
if self.recycleable_keys.is_empty() {
let mut test_index = 1;
let mut test_counter = self.counter.wrapping_add(test_index);
while self.buckets.contains_key(&test_counter) {
for i in 0..5000 {
test_index += i;
test_counter = self.counter.wrapping_add(test_index);
}
}
self.counter = self.counter.wrapping_add(test_index);
self.counter
} else {
self.recycleable_keys.pop().unwrap()
}
}
/// Append a new bucket to the bridge table, returning its index
pub fn new_bucket(&mut self, bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET]) -> u32 {
// Pick a random key to encrypt this bucket
@ -277,17 +331,18 @@ impl BridgeTable {
let mut key: [u8; 16] = [0; 16];
rng.fill_bytes(&mut key);
// Increase the counter to identify the bucket, wrap value if beyond u32::MAX
self.counter = self.counter.wrapping_add(1);
self.keys.insert(self.counter, key);
self.buckets.insert(self.counter, *bucket);
let index = self.find_next_available_key();
//self.counter = self.counter.wrapping_add(1);
self.keys.insert(index, key);
self.buckets.insert(index, *bucket);
// TODO: maybe we don't need this if the hashtable can keep track of available bridges
// Mark the new bridges as available
for (i, b) in bucket.iter().enumerate() {
if b.port > 0 {
if let Some(v) = self.reachable.get_mut(b) {
v.push((self.counter, i));
v.push((index, i));
} else {
let v = vec![(self.counter, i)];
let v = vec![(index, i)];
self.reachable.insert(*b, v);
}
}

View File

@ -445,6 +445,7 @@ impl BridgeAuth {
// Get the first spare and remove it from the spares set.
let spare = *self.bridge_table.spares.iter().next().unwrap();
self.bridge_table.spares.remove(&spare);
self.bridge_table.recycleable_keys.push(spare);
// Get the actual bridges from the spare bucket
let spare_bucket = match self.bridge_table.buckets.remove(&spare) {
Some(spare_bucket) => spare_bucket,
@ -567,6 +568,9 @@ impl BridgeAuth {
// set.
let spare = *self.bridge_table.spares.iter().next().unwrap();
self.bridge_table.spares.remove(&spare);
self.bridge_table
.blocked_keys
.push((*bucketnum, self.today()));
// Add a blockage migration from this bucket to the spare
self.blockage_migration_table
.table