Skip to content

Commit 2eba093

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 56db1ce commit 2eba093

File tree

5 files changed

+44
-49
lines changed

5 files changed

+44
-49
lines changed

mgmtd/src/bee_msg/register_target.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,33 @@ impl HandleWithResponse for RegisterTarget {
1111

1212
let (id, is_new) = app
1313
.write_tx(move |tx| {
14+
let reg_token = str::from_utf8(&self.reg_token)?;
15+
1416
// Do not do anything if the target already exists
1517
if let Some(id) = try_resolve_num_id(
1618
tx,
1719
EntityType::Target,
1820
NodeType::Storage,
1921
self.target_id.into(),
2022
)? {
23+
let stored_reg_token: Option<String> = tx.query_row(
24+
sql!(
25+
"SELECT reg_token FROM targets
26+
WHERE target_id = ?1 AND node_type = ?2"
27+
),
28+
rusqlite::params![id.num_id(), NodeType::Storage.sql_variant()],
29+
|row| row.get(0),
30+
)?;
31+
32+
if let Some(st) = stored_reg_token
33+
&& st != reg_token
34+
{
35+
bail!(
36+
"Storage target {id} has already been registered and its \
37+
registration token ({reg_token}) does not match the stored token ({st})"
38+
);
39+
}
40+
2141
return Ok((id.num_id().try_into()?, false));
2242
}
2343

@@ -26,11 +46,7 @@ impl HandleWithResponse for RegisterTarget {
2646
}
2747

2848
Ok((
29-
db::target::insert_storage(
30-
tx,
31-
self.target_id,
32-
Some(format!("target_{}", std::str::from_utf8(&self.alias)?).try_into()?),
33-
)?,
49+
db::target::insert_storage(tx, self.target_id, Some(reg_token))?,
3450
true,
3551
))
3652
})

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, None)?;
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 & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,18 @@ pub(crate) fn validate_ids(
4040
pub(crate) fn insert_meta(
4141
tx: &Transaction,
4242
target_id: TargetId,
43-
alias: Option<Alias>,
43+
reg_token: Option<&str>,
4444
) -> Result<()> {
4545
let target_id = if target_id == 0 {
4646
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));
5147
} else {
5248
target_id
5349
};
5450

5551
insert(
5652
tx,
5753
target_id,
58-
alias,
54+
reg_token,
5955
NodeTypeServer::Meta,
6056
Some(target_id.into()),
6157
)?;
@@ -78,45 +74,36 @@ pub(crate) fn insert_meta(
7874
pub(crate) fn insert_storage(
7975
tx: &Transaction,
8076
target_id: TargetId,
81-
alias: Option<Alias>,
77+
reg_token: Option<&str>,
8278
) -> Result<TargetId> {
8379
let target_id = if target_id == 0 {
8480
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);
8981
} else {
9082
target_id
9183
};
9284

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

9587
Ok(target_id)
9688
}
9789

98-
pub(crate) fn insert(
90+
fn insert(
9991
tx: &Transaction,
10092
target_id: TargetId,
101-
alias: Option<Alias>,
93+
reg_token: Option<&str>,
10294
node_type: NodeTypeServer,
10395
// This is optional because storage targets come "unmapped"
10496
node_id: Option<NodeId>,
10597
) -> Result<()> {
10698
anyhow::ensure!(target_id > 0, "A target id must be > 0");
10799

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-
100+
let alias = format!("target_{}_{target_id}", node_type.user_str()).try_into()?;
114101
let new_uid = entity::insert(tx, EntityType::Target, &alias)?;
115102

116103
tx.execute(
117104
sql!(
118-
"INSERT INTO targets (target_uid, node_type, target_id, node_id, pool_id)
119-
VALUES (?1, ?2, ?3, ?4, ?5)"
105+
"INSERT INTO targets (target_uid, node_type, target_id, node_id, pool_id, reg_token)
106+
VALUES (?1, ?2, ?3, ?4, ?5, ?6)"
120107
),
121108
params![
122109
new_uid,
@@ -127,7 +114,8 @@ pub(crate) fn insert(
127114
Some(1)
128115
} else {
129116
None
130-
}
117+
},
118+
reg_token
131119
],
132120
)?;
133121

@@ -287,11 +275,10 @@ mod test {
287275
#[test]
288276
fn set_get_meta() {
289277
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();
278+
super::insert_meta(tx, 1, None).unwrap_err();
279+
super::insert_meta(tx, 99, None).unwrap();
280+
// existing id
281+
super::insert_meta(tx, 99, None).unwrap_err();
295282

296283
let targets: i64 = tx
297284
.query_row(sql!("SELECT COUNT(*) FROM meta_targets"), [], |row| {
@@ -306,15 +293,11 @@ mod test {
306293
#[test]
307294
fn set_get_storage_and_map() {
308295
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();
296+
let new_target_id = super::insert_storage(tx, 0, Some("new_storage_target")).unwrap();
297+
super::insert_storage(tx, 1000, Some("new_storage_target_2")).unwrap();
314298

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

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

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)