Skip to content

Commit 0662a6a

Browse files
committed
fix: Use registration token to prevent double target id use
On storage target registration, the node sends a "node string id" / alias which is generated locally on the node. This commit uses that as a registration token to "ensure" that a once registered target id is not reused with a different target - if the registration token is already known, the RegisterNodeMsg will fail. This restores old managements behavior. Note that the RegisterNodeMsg actually doesn't do anything on an already known target (and didn't before this commit) besides logging. It is up to the server nodes to abort on a failing RegisterNodeMsg.
1 parent 56cb7a2 commit 0662a6a

File tree

6 files changed

+46
-55
lines changed

6 files changed

+46
-55
lines changed

mgmtd/src/bee_msg/node.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ client version < 8.0)"
246246
);
247247
};
248248

249-
db::target::insert_meta(tx, target_id, None)?;
249+
db::target::insert_meta(tx, target_id)?;
250250
}
251251

252252
(node, true)

mgmtd/src/bee_msg/target.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,33 @@ impl HandleWithResponse for RegisterTarget {
127127
let (id, is_new) = ctx
128128
.db
129129
.write_tx(move |tx| {
130+
let reg_token = str::from_utf8(&self.reg_token)?;
131+
130132
// Do not do anything if the target already exists
131133
if let Some(id) = try_resolve_num_id(
132134
tx,
133135
EntityType::Target,
134136
NodeType::Storage,
135137
self.target_id.into(),
136138
)? {
139+
let stored_reg_token: Option<String> = tx.query_row(
140+
sql!(
141+
"SELECT reg_token FROM targets
142+
WHERE target_id = ?1 AND node_type = ?2"
143+
),
144+
rusqlite::params![id.num_id(), NodeType::Storage.sql_variant()],
145+
|row| row.get(0),
146+
)?;
147+
148+
if let Some(st) = stored_reg_token
149+
&& st != reg_token
150+
{
151+
bail!(
152+
"Storage target {id} has already been registered and its \
153+
registration token ({reg_token}) does not match the stored token ({st})"
154+
);
155+
}
156+
137157
return Ok((id.num_id().try_into()?, false));
138158
}
139159

@@ -142,11 +162,7 @@ impl HandleWithResponse for RegisterTarget {
142162
}
143163

144164
Ok((
145-
db::target::insert_storage(
146-
tx,
147-
self.target_id,
148-
Some(format!("target_{}", std::str::from_utf8(&self.alias)?).try_into()?),
149-
)?,
165+
db::target::insert_storage(tx, self.target_id, Some(reg_token))?,
150166
true,
151167
))
152168
})
@@ -155,7 +171,7 @@ impl HandleWithResponse for RegisterTarget {
155171
if is_new {
156172
log::info!("Registered new storage target with Id {id}");
157173
} else {
158-
log::debug!("Re-registered existing storage target with Id {id}");
174+
log::debug!("Re-registered existing storage target with Id {id}",);
159175
}
160176

161177
Ok(RegisterTargetResp { id })

mgmtd/src/db/import_v7.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,8 @@ fn meta_nodes(tx: &Transaction, f: &Path) -> Result<(NodeId, bool)> {
143143
"{num_id} is not a valid numeric meta node/target id (must be between 1 and 65535)",
144144
);
145145
};
146-
target::insert(
147-
tx,
148-
target_id,
149-
None,
150-
NodeTypeServer::Meta,
151-
Some(target_id.into()),
152-
)?;
146+
147+
target::insert_meta(tx, target_id)?;
153148
}
154149

155150
if root_id == 0 {

mgmtd/src/db/schema/4.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE targets ADD COLUMN reg_token TEXT;

mgmtd/src/db/target.rs

Lines changed: 19 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -37,25 +37,17 @@ pub(crate) fn validate_ids(
3737
///
3838
/// BeeGFS doesn't really support meta targets at the moment, so there always must be exactly one
3939
/// meta target per meta node with their IDs being the same.
40-
pub(crate) fn insert_meta(
41-
tx: &Transaction,
42-
target_id: TargetId,
43-
alias: Option<Alias>,
44-
) -> Result<()> {
40+
pub(crate) fn insert_meta(tx: &Transaction, target_id: TargetId) -> Result<()> {
4541
let target_id = if target_id == 0 {
4642
misc::find_new_id(tx, "targets", "target_id", NodeType::Meta, 1..=0xFFFF)?
47-
} else if try_resolve_num_id(tx, EntityType::Target, NodeType::Meta, target_id.into())?
48-
.is_some()
49-
{
50-
bail!(TypedError::value_exists("numeric target id", target_id));
5143
} else {
5244
target_id
5345
};
5446

5547
insert(
5648
tx,
5749
target_id,
58-
alias,
50+
None,
5951
NodeTypeServer::Meta,
6052
Some(target_id.into()),
6153
)?;
@@ -78,45 +70,36 @@ pub(crate) fn insert_meta(
7870
pub(crate) fn insert_storage(
7971
tx: &Transaction,
8072
target_id: TargetId,
81-
alias: Option<Alias>,
73+
reg_token: Option<&str>,
8274
) -> Result<TargetId> {
8375
let target_id = if target_id == 0 {
8476
misc::find_new_id(tx, "targets", "target_id", NodeType::Storage, 1..=0xFFFF)?
85-
} else if try_resolve_num_id(tx, EntityType::Target, NodeType::Storage, target_id.into())?
86-
.is_some()
87-
{
88-
return Ok(target_id);
8977
} else {
9078
target_id
9179
};
9280

93-
insert(tx, target_id, alias, NodeTypeServer::Storage, None)?;
81+
insert(tx, target_id, reg_token, NodeTypeServer::Storage, None)?;
9482

9583
Ok(target_id)
9684
}
9785

98-
pub(crate) fn insert(
86+
fn insert(
9987
tx: &Transaction,
10088
target_id: TargetId,
101-
alias: Option<Alias>,
89+
reg_token: Option<&str>,
10290
node_type: NodeTypeServer,
10391
// This is optional because storage targets come "unmapped"
10492
node_id: Option<NodeId>,
10593
) -> Result<()> {
10694
anyhow::ensure!(target_id > 0, "A target id must be > 0");
10795

108-
let alias = if let Some(alias) = alias {
109-
alias
110-
} else {
111-
format!("target_{}_{}", node_type.user_str(), target_id).try_into()?
112-
};
113-
96+
let alias = format!("target_{}_{target_id}", node_type.user_str()).try_into()?;
11497
let new_uid = entity::insert(tx, EntityType::Target, &alias)?;
11598

11699
tx.execute(
117100
sql!(
118-
"INSERT INTO targets (target_uid, node_type, target_id, node_id, pool_id)
119-
VALUES (?1, ?2, ?3, ?4, ?5)"
101+
"INSERT INTO targets (target_uid, node_type, target_id, node_id, pool_id, reg_token)
102+
VALUES (?1, ?2, ?3, ?4, ?5, ?6)"
120103
),
121104
params![
122105
new_uid,
@@ -127,7 +110,8 @@ pub(crate) fn insert(
127110
Some(1)
128111
} else {
129112
None
130-
}
113+
},
114+
reg_token
131115
],
132116
)?;
133117

@@ -287,11 +271,10 @@ mod test {
287271
#[test]
288272
fn set_get_meta() {
289273
with_test_data(|tx| {
290-
super::insert_meta(tx, 1, Some("existing_meta_target".try_into().unwrap()))
291-
.unwrap_err();
292-
super::insert_meta(tx, 99, Some("new_meta_target".try_into().unwrap())).unwrap();
293-
// existing alias
294-
super::insert_meta(tx, 99, Some("new_meta_target".try_into().unwrap())).unwrap_err();
274+
super::insert_meta(tx, 1).unwrap_err();
275+
super::insert_meta(tx, 99).unwrap();
276+
// existing id
277+
super::insert_meta(tx, 99).unwrap_err();
295278

296279
let targets: i64 = tx
297280
.query_row(sql!("SELECT COUNT(*) FROM meta_targets"), [], |row| {
@@ -306,15 +289,11 @@ mod test {
306289
#[test]
307290
fn set_get_storage_and_map() {
308291
with_test_data(|tx| {
309-
let new_target_id =
310-
super::insert_storage(tx, 0, Some("new_storage_target".try_into().unwrap()))
311-
.unwrap();
312-
super::insert_storage(tx, 1000, Some("new_storage_target_2".try_into().unwrap()))
313-
.unwrap();
292+
let new_target_id = super::insert_storage(tx, 0, Some("new_storage_target")).unwrap();
293+
super::insert_storage(tx, 1000, Some("new_storage_target_2")).unwrap();
314294

315-
// existing alias
316-
super::insert_storage(tx, 0, Some("new_storage_target".try_into().unwrap()))
317-
.unwrap_err();
295+
// existing id
296+
super::insert_storage(tx, 1000, Some("new_storage_target")).unwrap_err();
318297

319298
super::update_storage_node_mappings(tx, &[new_target_id, 1000], 1).unwrap();
320299

shared/src/bee_msg/target.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ impl Deserializable for TargetReachabilityState {
9494
#[derive(Clone, Debug, Default, PartialEq, Eq, BeeSerde)]
9595
pub struct RegisterTarget {
9696
#[bee_serde(as = CStr<0>)]
97-
pub alias: Vec<u8>,
97+
pub reg_token: Vec<u8>,
9898
pub target_id: TargetId,
9999
}
100100

0 commit comments

Comments
 (0)