feat: drop unknown typed frames instead of storing as chat
Classify decrypted plaintext before append_message so loc/prf/inv/rcp/png and unknown xxx[space] prefixes never land in the message log.
This commit is contained in:
parent
cbbf3f6baa
commit
c9d85d9ae5
4 changed files with 105 additions and 18 deletions
39
src/dispatch.rs
Normal file
39
src/dispatch.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
//! Classify decrypted application plaintext before it hits the message log.
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Kind {
|
||||||
|
Chat,
|
||||||
|
Loc,
|
||||||
|
Profile,
|
||||||
|
Invoice,
|
||||||
|
Receipt,
|
||||||
|
Ping,
|
||||||
|
Drop,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn classify(pt: &[u8]) -> Kind {
|
||||||
|
if pt.starts_with(b"loc ") {
|
||||||
|
return Kind::Loc;
|
||||||
|
}
|
||||||
|
if pt.starts_with(b"prf ") {
|
||||||
|
return Kind::Profile;
|
||||||
|
}
|
||||||
|
if pt.starts_with(b"inv ") {
|
||||||
|
return Kind::Invoice;
|
||||||
|
}
|
||||||
|
if pt.starts_with(b"rcp ") {
|
||||||
|
return Kind::Receipt;
|
||||||
|
}
|
||||||
|
if pt.starts_with(b"png ") {
|
||||||
|
return Kind::Ping;
|
||||||
|
}
|
||||||
|
if pt.len() >= 4
|
||||||
|
&& pt[0].is_ascii_lowercase()
|
||||||
|
&& pt[1].is_ascii_lowercase()
|
||||||
|
&& pt[2].is_ascii_lowercase()
|
||||||
|
&& pt[3] == b' '
|
||||||
|
{
|
||||||
|
return Kind::Drop;
|
||||||
|
}
|
||||||
|
Kind::Chat
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod dispatch;
|
||||||
pub mod frame;
|
pub mod frame;
|
||||||
pub mod hs;
|
pub mod hs;
|
||||||
pub mod loc;
|
pub mod loc;
|
||||||
|
|
|
||||||
10
src/node.rs
10
src/node.rs
|
|
@ -9,6 +9,7 @@ use futures::io::{AsyncRead, AsyncWrite};
|
||||||
use tor_cell::relaycell::msg::Connected;
|
use tor_cell::relaycell::msg::Connected;
|
||||||
use tor_hsservice::{RunningOnionService, handle_rend_requests};
|
use tor_hsservice::{RunningOnionService, handle_rend_requests};
|
||||||
|
|
||||||
|
use crate::dispatch::{self, Kind};
|
||||||
use crate::frame;
|
use crate::frame;
|
||||||
use crate::hs::{self, Client, HS_PORT};
|
use crate::hs::{self, Client, HS_PORT};
|
||||||
use crate::loc;
|
use crate::loc;
|
||||||
|
|
@ -308,6 +309,8 @@ impl Node {
|
||||||
.map_err(session_err)?;
|
.map_err(session_err)?;
|
||||||
let ct = frame::read_frame(stream).await.map_err(|e| e.to_string())?;
|
let ct = frame::read_frame(stream).await.map_err(|e| e.to_string())?;
|
||||||
let pt = sess.decrypt(&ct).map_err(session_err)?;
|
let pt = sess.decrypt(&ct).map_err(session_err)?;
|
||||||
|
match dispatch::classify(&pt) {
|
||||||
|
Kind::Loc => {
|
||||||
if let Some(loc) = loc::decode(&pt) {
|
if let Some(loc) = loc::decode(&pt) {
|
||||||
let applied = store.lock().map_err(|e| e.to_string())?.apply_loc(
|
let applied = store.lock().map_err(|e| e.to_string())?.apply_loc(
|
||||||
&sess.peer_identity,
|
&sess.peer_identity,
|
||||||
|
|
@ -320,8 +323,10 @@ impl Node {
|
||||||
Ok(false) => eprintln!("loc dropped (bad sig, stale ts, or unknown friend)"),
|
Ok(false) => eprintln!("loc dropped (bad sig, stale ts, or unknown friend)"),
|
||||||
Err(e) => return Err(e.to_string()),
|
Err(e) => return Err(e.to_string()),
|
||||||
}
|
}
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Kind::Chat => {
|
||||||
store
|
store
|
||||||
.lock()
|
.lock()
|
||||||
.map_err(|e| e.to_string())?
|
.map_err(|e| e.to_string())?
|
||||||
|
|
@ -329,6 +334,9 @@ impl Node {
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Kind::Profile | Kind::Invoice | Kind::Receipt | Kind::Ping | Kind::Drop => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_rend(
|
fn spawn_rend(
|
||||||
|
|
|
||||||
39
tests/dispatch.rs
Normal file
39
tests/dispatch.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
//! M6: typed-frame dispatcher — classify before append_message.
|
||||||
|
|
||||||
|
use onionwire::dispatch::{classify, Kind};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn chat_is_chat() {
|
||||||
|
assert_eq!(classify(b"hello wire"), Kind::Chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn loc_still_loc() {
|
||||||
|
assert_eq!(classify(b"loc abc.onion\n1\n00"), Kind::Loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unknown_typed_prefix_is_drop() {
|
||||||
|
assert_eq!(classify(b"zzz not a real type"), Kind::Drop);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn short_or_binary_without_prefix_is_chat() {
|
||||||
|
assert_eq!(classify(b"hi"), Kind::Chat);
|
||||||
|
assert_eq!(classify(&[0xff, 0xfe]), Kind::Chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn known_prefixes_are_typed() {
|
||||||
|
assert_eq!(classify(b"prf name"), Kind::Profile);
|
||||||
|
assert_eq!(classify(b"inv 1"), Kind::Invoice);
|
||||||
|
assert_eq!(classify(b"rcp tx"), Kind::Receipt);
|
||||||
|
assert_eq!(classify(b"png 1"), Kind::Ping);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn uppercase_or_digit_prefix_is_chat() {
|
||||||
|
assert_eq!(classify(b"ZZZ not typed"), Kind::Chat);
|
||||||
|
assert_eq!(classify(b"ab1 leftover"), Kind::Chat);
|
||||||
|
assert_eq!(classify(b"abcd"), Kind::Chat);
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue