🚨 cargo check pass
parent
25a8a035b9
commit
843fddb568
|
@ -281,7 +281,7 @@ version = "3.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1631ca6e3c59112501a9d87fd86f21591ff77acd31331e8a73f8d80a65bbdd71"
|
checksum = "1631ca6e3c59112501a9d87fd86f21591ff77acd31331e8a73f8d80a65bbdd71"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nix 0.26.1",
|
"nix",
|
||||||
"windows-sys 0.42.0",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -774,19 +774,6 @@ dependencies = [
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "insecure_chat"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"hyper",
|
|
||||||
"mac_address",
|
|
||||||
"nix 0.25.1",
|
|
||||||
"ptth_diceware",
|
|
||||||
"rand",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
|
@ -866,16 +853,6 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mac_address"
|
|
||||||
version = "1.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b238e3235c8382b7653c6408ed1b08dd379bdb9fdf990fb0bbae3db2cc0ae963"
|
|
||||||
dependencies = [
|
|
||||||
"nix 0.23.2",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "maplit"
|
name = "maplit"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
@ -897,15 +874,6 @@ version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memoffset"
|
|
||||||
version = "0.6.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "metrics_test"
|
name = "metrics_test"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -950,33 +918,6 @@ dependencies = [
|
||||||
"tempfile",
|
"tempfile",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nix"
|
|
||||||
version = "0.23.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"cc",
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"memoffset",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nix"
|
|
||||||
version = "0.25.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"bitflags",
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"memoffset",
|
|
||||||
"pin-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.26.1"
|
version = "0.26.1"
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "insecure_chat"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
hyper = { version = "0.14.20", features = ["http1", "server", "tcp"] }
|
|
||||||
mac_address = "1.1.4"
|
|
||||||
nix = "0.25.0"
|
|
||||||
ptth_diceware = { path = "../ptth_diceware" }
|
|
||||||
rand = "0.8.5"
|
|
||||||
thiserror = "1.0.37"
|
|
||||||
tokio = { version = "1.21.2", features = ["net", "rt-multi-thread", "fs"] }
|
|
|
@ -1,125 +0,0 @@
|
||||||
// IP address module
|
|
||||||
// Copied from the `lookaround` project
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
net::Ipv4Addr,
|
|
||||||
process::Command,
|
|
||||||
str::FromStr,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive (Debug, thiserror::Error)]
|
|
||||||
pub enum Error {
|
|
||||||
#[error (transparent)]
|
|
||||||
Io (#[from] std::io::Error),
|
|
||||||
#[error (transparent)]
|
|
||||||
FromUtf8 (#[from] std::string::FromUtf8Error),
|
|
||||||
#[error ("Self-IP detection is not implemented on Mac OS")]
|
|
||||||
NotImplementedOnMac,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
pub fn get_ips () -> Result <Vec <Ipv4Addr>, Error> {
|
|
||||||
let output = linux::get_ip_addr_output ()?;
|
|
||||||
|
|
||||||
Ok (linux::parse_ip_addr_output (&output))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
pub fn get_ips () -> Result <Vec <Ipv4Addr>, Error> {
|
|
||||||
Err (Error::NotImplementedOnMac)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
pub fn get_ips () -> Result <Vec <Ipv4Addr>, Error> {
|
|
||||||
let output = windows::get_ip_config_output ()?;
|
|
||||||
|
|
||||||
Ok (windows::parse_ip_config_output (&output))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
pub mod linux {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub fn get_ip_addr_output () -> Result <String, Error> {
|
|
||||||
let output = Command::new ("ip")
|
|
||||||
.arg ("addr")
|
|
||||||
.output ()?;
|
|
||||||
let output = output.stdout.as_slice ();
|
|
||||||
let output = String::from_utf8 (output.to_vec ())?;
|
|
||||||
Ok (output)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_ip_addr_output (output: &str) -> Vec <Ipv4Addr> {
|
|
||||||
// I wrote this in FP style because I was bored.
|
|
||||||
|
|
||||||
output.lines ()
|
|
||||||
.map (|l| l.trim_start ())
|
|
||||||
.filter_map (|l| l.strip_prefix ("inet "))
|
|
||||||
.filter_map (|l| l.find ('/').map (|x| &l [0..x]))
|
|
||||||
.filter_map (|l| Ipv4Addr::from_str (l).ok ())
|
|
||||||
.filter (|a| ! a.is_loopback ())
|
|
||||||
.collect ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
pub mod windows {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub fn get_ip_config_output () -> Result <String, Error> {
|
|
||||||
let output = Command::new ("ipconfig")
|
|
||||||
.output ()?;
|
|
||||||
let output = output.stdout.as_slice ();
|
|
||||||
let output = String::from_utf8 (output.to_vec ())?;
|
|
||||||
Ok (output)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_ip_config_output (output: &str) -> Vec <Ipv4Addr> {
|
|
||||||
let mut addrs = vec! [];
|
|
||||||
|
|
||||||
for line in output.lines () {
|
|
||||||
let line = line.trim_start ();
|
|
||||||
|
|
||||||
// Maybe only works on English locales?
|
|
||||||
if ! line.starts_with ("IPv4 Address") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let colon_pos = match line.find (':') {
|
|
||||||
None => continue,
|
|
||||||
Some (x) => x,
|
|
||||||
};
|
|
||||||
let line = &line [colon_pos + 2..];
|
|
||||||
|
|
||||||
let addr = match Ipv4Addr::from_str (line) {
|
|
||||||
Err (_) => continue,
|
|
||||||
Ok (x) => x,
|
|
||||||
};
|
|
||||||
|
|
||||||
addrs.push (addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
addrs
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg (test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test () {
|
|
||||||
for (input, expected) in [
|
|
||||||
(
|
|
||||||
r"
|
|
||||||
IPv4 Address . . .. . . . : 192.168.1.1
|
|
||||||
",
|
|
||||||
vec! [
|
|
||||||
Ipv4Addr::new (192, 168, 1, 1),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
] {
|
|
||||||
let actual = parse_ip_config_output (input);
|
|
||||||
assert_eq! (actual, expected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,375 +0,0 @@
|
||||||
use std::{
|
|
||||||
collections::*,
|
|
||||||
net::{
|
|
||||||
Ipv4Addr,
|
|
||||||
SocketAddrV4,
|
|
||||||
},
|
|
||||||
sync::Arc,
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
use hyper::{
|
|
||||||
Body,
|
|
||||||
Method,
|
|
||||||
Request,
|
|
||||||
Response,
|
|
||||||
Server,
|
|
||||||
StatusCode,
|
|
||||||
service::{
|
|
||||||
make_service_fn,
|
|
||||||
service_fn,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use tokio::{
|
|
||||||
net::UdpSocket,
|
|
||||||
sync::RwLock,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod ip;
|
|
||||||
mod tlv;
|
|
||||||
|
|
||||||
fn main () -> Result <(), Error>
|
|
||||||
{
|
|
||||||
let mut args = std::env::args ();
|
|
||||||
let mut bail_unknown = true;
|
|
||||||
let mut last_unknown = None;
|
|
||||||
let mut name = ptth_diceware::passphrase ("_", 3);
|
|
||||||
let mut subcommand_count = 0;
|
|
||||||
let mut subcommand = None;
|
|
||||||
|
|
||||||
args.next ();
|
|
||||||
while let Some (arg) = args.next () {
|
|
||||||
if arg == "--ignore-unknown" {
|
|
||||||
bail_unknown = false;
|
|
||||||
}
|
|
||||||
if arg == "--name" {
|
|
||||||
name = args.next ().unwrap ().to_string ();
|
|
||||||
}
|
|
||||||
else if arg == "peer" {
|
|
||||||
subcommand = Some (Subcommand::Peer);
|
|
||||||
subcommand_count += 1;
|
|
||||||
}
|
|
||||||
else if arg == "receiver" {
|
|
||||||
subcommand = Some (Subcommand::Receiver);
|
|
||||||
subcommand_count += 1;
|
|
||||||
}
|
|
||||||
else if arg == "sender" {
|
|
||||||
subcommand = Some (Subcommand::Sender);
|
|
||||||
subcommand_count += 1;
|
|
||||||
}
|
|
||||||
else if arg == "spy" {
|
|
||||||
subcommand = Some (Subcommand::Spy);
|
|
||||||
subcommand_count += 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
last_unknown = Some (arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if bail_unknown {
|
|
||||||
if let Some (last_unknown) = last_unknown {
|
|
||||||
eprintln! ("Unknown argument `{}`", last_unknown);
|
|
||||||
return Err (Error::Args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if subcommand_count >= 2 {
|
|
||||||
eprintln! ("Detected {} subcommands in arguments", subcommand_count);
|
|
||||||
return Err (Error::Args)
|
|
||||||
}
|
|
||||||
|
|
||||||
let rt = tokio::runtime::Runtime::new ()?;
|
|
||||||
|
|
||||||
let params = Params::default ();
|
|
||||||
|
|
||||||
rt.block_on (async {
|
|
||||||
if let Some (cmd) = subcommand {
|
|
||||||
return match cmd {
|
|
||||||
Subcommand::Peer => peer (params).await,
|
|
||||||
Subcommand::Receiver => receiver (params).await,
|
|
||||||
Subcommand::Sender => sender (params).await,
|
|
||||||
Subcommand::Spy => spy (params),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
println! ("Name is `{}`", name);
|
|
||||||
|
|
||||||
Ok::<_, Error> (())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok (())
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Subcommand {
|
|
||||||
Peer,
|
|
||||||
Receiver,
|
|
||||||
Sender,
|
|
||||||
Spy,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Params {
|
|
||||||
multicast_group: (Ipv4Addr, u16),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Params {
|
|
||||||
fn default () -> Self {
|
|
||||||
let multicast_group = (Ipv4Addr::new (225, 100, 99, 98), 9041);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
multicast_group,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn peer (params: Params) -> Result <(), Error>
|
|
||||||
{
|
|
||||||
use rand::Rng;
|
|
||||||
|
|
||||||
let mut id = [0];
|
|
||||||
rand::thread_rng ().try_fill (&mut id).or (Err (Error::Rand))?;
|
|
||||||
let (multicast_addr, multicast_port) = params.multicast_group;
|
|
||||||
let socket = tokio::net::UdpSocket::bind (SocketAddrV4::new (Ipv4Addr::UNSPECIFIED, multicast_port)).await?;
|
|
||||||
|
|
||||||
socket.join_multicast_v4 (multicast_addr, Ipv4Addr::UNSPECIFIED)?;
|
|
||||||
eprintln! ("Multicast group is {:?}", params.multicast_group);
|
|
||||||
eprintln! ("Local addr is {}", socket.local_addr ()?);
|
|
||||||
|
|
||||||
let peer = Peer {
|
|
||||||
id: id [0],
|
|
||||||
outbox: Outbox {
|
|
||||||
index: 1000,
|
|
||||||
messages: Default::default (),
|
|
||||||
}.into (),
|
|
||||||
params,
|
|
||||||
socket,
|
|
||||||
};
|
|
||||||
|
|
||||||
eprintln! ("Random peer ID is {}", peer.id);
|
|
||||||
|
|
||||||
let state = Arc::new (peer);
|
|
||||||
|
|
||||||
{
|
|
||||||
let state = Arc::clone (&state);
|
|
||||||
tokio::spawn (async move {
|
|
||||||
let mut interval = tokio::time::interval (Duration::from_secs (25));
|
|
||||||
interval.set_missed_tick_behavior (tokio::time::MissedTickBehavior::Skip);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
interval.tick ().await;
|
|
||||||
|
|
||||||
state.send_multicast (&tlv::Message::IAmOnline { peer_id: state.id }).await.ok ();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let state = Arc::clone (&state);
|
|
||||||
tokio::spawn (async move {
|
|
||||||
loop {
|
|
||||||
let mut buf = vec! [0u8; 2048];
|
|
||||||
let (bytes_recved, addr) = match state.socket.recv_from (&mut buf).await
|
|
||||||
{
|
|
||||||
Err (_) => {
|
|
||||||
tokio::time::sleep (Duration::from_secs (10)).await;
|
|
||||||
continue;
|
|
||||||
},
|
|
||||||
Ok (x) => x,
|
|
||||||
};
|
|
||||||
let buf = &buf [0..bytes_recved];
|
|
||||||
|
|
||||||
let msg = match tlv::decode (buf) {
|
|
||||||
Err (_) => {
|
|
||||||
eprintln! ("ZAT4ERXR Couldn't decode message");
|
|
||||||
continue;
|
|
||||||
},
|
|
||||||
Ok (x) => x,
|
|
||||||
};
|
|
||||||
|
|
||||||
println! ("Received {:?}", msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let make_svc = make_service_fn (|_conn| {
|
|
||||||
let state = Arc::clone (&state);
|
|
||||||
|
|
||||||
async {
|
|
||||||
Ok::<_, String> (service_fn (move |req| {
|
|
||||||
let state = state.clone ();
|
|
||||||
peer_handle_all (req, state)
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let addr = std::net::SocketAddr::from (([127, 0, 0, 1], multicast_port));
|
|
||||||
let server = Server::bind (&addr)
|
|
||||||
.serve (make_svc);
|
|
||||||
|
|
||||||
eprintln! ("Local UI on {}", addr);
|
|
||||||
|
|
||||||
server.await?;
|
|
||||||
|
|
||||||
Ok (())
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Peer {
|
|
||||||
id: u32,
|
|
||||||
outbox: RwLock <Outbox>,
|
|
||||||
params: Params,
|
|
||||||
socket: UdpSocket,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Peer {
|
|
||||||
async fn send_multicast (&self, msg: &tlv::Message) -> Result <(), Error>
|
|
||||||
{
|
|
||||||
let msg = tlv::encode (&msg)?;
|
|
||||||
self.socket.send_to (&msg, self.params.multicast_group).await?;
|
|
||||||
Ok (())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Outbox {
|
|
||||||
index: u32,
|
|
||||||
messages: VecDeque <SentMessage>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SentMessage {
|
|
||||||
index: u32,
|
|
||||||
body: Vec <u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn peer_handle_all (req: Request <Body>, state: Arc <Peer>)
|
|
||||||
-> Result <Response <Body>, Error>
|
|
||||||
{
|
|
||||||
if req.method () == Method::POST {
|
|
||||||
if req.uri () == "/paste" {
|
|
||||||
let body = hyper::body::to_bytes (req.into_body ()).await?;
|
|
||||||
if body.len () > 1024 {
|
|
||||||
let resp = Response::builder ()
|
|
||||||
.status (StatusCode::BAD_REQUEST)
|
|
||||||
.body (Body::from ("Message body must be <= 1024 bytes"))?;
|
|
||||||
return Ok (resp);
|
|
||||||
}
|
|
||||||
let body = body.to_vec ();
|
|
||||||
|
|
||||||
let msg_index;
|
|
||||||
{
|
|
||||||
let mut outbox = state.outbox.write ().await;
|
|
||||||
let msg = SentMessage {
|
|
||||||
index: outbox.index,
|
|
||||||
body: body.clone (),
|
|
||||||
};
|
|
||||||
msg_index = msg.index;
|
|
||||||
outbox.messages.push_back (msg);
|
|
||||||
if outbox.messages.len () > 10 {
|
|
||||||
outbox.messages.pop_front ();
|
|
||||||
}
|
|
||||||
outbox.index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
match state.send_multicast (&tlv::Message::IHaveMessage {
|
|
||||||
peer_id: state.id,
|
|
||||||
msg_index,
|
|
||||||
body,
|
|
||||||
}).await {
|
|
||||||
Ok (_) => (),
|
|
||||||
Err (_) => return Ok (
|
|
||||||
Response::builder ()
|
|
||||||
.status (StatusCode::BAD_REQUEST)
|
|
||||||
.body (Body::from ("Can't encode message"))?
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok (Response::new (format! ("Pasted message {}\n", msg_index).into ()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok (Response::new (":V\n".into ()))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn receiver (params: Params) -> Result <(), Error>
|
|
||||||
{
|
|
||||||
let (multicast_addr, multicast_port) = params.multicast_group;
|
|
||||||
let socket = tokio::net::UdpSocket::bind (SocketAddrV4::new (Ipv4Addr::UNSPECIFIED, multicast_port)).await?;
|
|
||||||
|
|
||||||
socket.join_multicast_v4 (multicast_addr, Ipv4Addr::UNSPECIFIED)?;
|
|
||||||
eprintln! ("Multicast group is {:?}", params.multicast_group);
|
|
||||||
eprintln! ("Local addr is {}", socket.local_addr ()?);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let mut buf = vec! [0u8; 2048];
|
|
||||||
|
|
||||||
let (bytes_recved, remote_addr) = socket.recv_from (&mut buf).await?;
|
|
||||||
buf.truncate (bytes_recved);
|
|
||||||
|
|
||||||
println! ("Received {} bytes from {}", bytes_recved, remote_addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn sender (params: Params) -> Result <(), Error>
|
|
||||||
{
|
|
||||||
let (multicast_addr, multicast_port) = params.multicast_group;
|
|
||||||
let socket = tokio::net::UdpSocket::bind (SocketAddrV4::new (Ipv4Addr::UNSPECIFIED, 0)).await?;
|
|
||||||
|
|
||||||
socket.join_multicast_v4 (multicast_addr, Ipv4Addr::UNSPECIFIED)?;
|
|
||||||
eprintln! ("Multicast group is {:?}", params.multicast_group);
|
|
||||||
eprintln! ("Local addr is {}", socket.local_addr ()?);
|
|
||||||
|
|
||||||
socket.send_to (&[], params.multicast_group).await?;
|
|
||||||
|
|
||||||
Ok (())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn spy (params: Params) -> Result <(), Error>
|
|
||||||
{
|
|
||||||
let (multicast_addr, multicast_port) = params.multicast_group;
|
|
||||||
|
|
||||||
let socket = match std::net::UdpSocket::bind (SocketAddrV4::new (Ipv4Addr::UNSPECIFIED, multicast_port)) {
|
|
||||||
Ok (x) => x,
|
|
||||||
Err (e) => if e.kind () == std::io::ErrorKind::AddrInUse {
|
|
||||||
eprintln! ("Address in use. You can only run 1 instance of Insecure Chat at a time, even in spy mode.");
|
|
||||||
return Err (Error::AddrInUse);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Err (e.into ());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for bind_addr in ip::get_ips ()? {
|
|
||||||
socket.join_multicast_v4 (&multicast_addr, &bind_addr)?;
|
|
||||||
// eprintln! ("Joined multicast with {}", bind_addr);
|
|
||||||
}
|
|
||||||
eprintln! ("Multicast addr is {}", multicast_addr);
|
|
||||||
eprintln! ("Local addr is {}", socket.local_addr ()?);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let mut buf = vec! [0u8; 2048];
|
|
||||||
|
|
||||||
eprintln! ("Listening for UDP packets...");
|
|
||||||
let (bytes_recved, remote_addr) = socket.recv_from (&mut buf)?;
|
|
||||||
buf.truncate (bytes_recved);
|
|
||||||
|
|
||||||
println! ("Received {} bytes from {}", bytes_recved, remote_addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive (Debug, thiserror::Error)]
|
|
||||||
enum Error {
|
|
||||||
#[error ("Address in use")]
|
|
||||||
AddrInUse,
|
|
||||||
#[error ("CLI args")]
|
|
||||||
Args,
|
|
||||||
#[error (transparent)]
|
|
||||||
Hyper (#[from] hyper::Error),
|
|
||||||
#[error (transparent)]
|
|
||||||
HyperHttp (#[from] hyper::http::Error),
|
|
||||||
#[error (transparent)]
|
|
||||||
Io (#[from] std::io::Error),
|
|
||||||
#[error (transparent)]
|
|
||||||
Ip (#[from] ip::Error),
|
|
||||||
#[error ("Randomness")]
|
|
||||||
Rand,
|
|
||||||
#[error (transparent)]
|
|
||||||
Tlv (#[from] tlv::Error),
|
|
||||||
}
|
|
|
@ -1,122 +0,0 @@
|
||||||
// A crummy ad-hoc TLV cause I'm lazy and these are fun
|
|
||||||
|
|
||||||
#[derive (Debug, PartialEq)]
|
|
||||||
pub enum Message {
|
|
||||||
IAmOnline {
|
|
||||||
peer_id: u32,
|
|
||||||
},
|
|
||||||
IHaveMessage {
|
|
||||||
peer_id: u32,
|
|
||||||
msg_index: u32,
|
|
||||||
body: Vec <u8>,
|
|
||||||
},
|
|
||||||
IAcknowledgeYourMessage {
|
|
||||||
msg_index: u32,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive (Debug, thiserror::Error)]
|
|
||||||
pub enum Error {
|
|
||||||
#[error ("Bad magic number")]
|
|
||||||
BadMagic,
|
|
||||||
#[error ("Data is too big to encode / decode")]
|
|
||||||
DataTooBig,
|
|
||||||
#[error ("Required field missing while decoding")]
|
|
||||||
MissingField,
|
|
||||||
#[error ("No type in TLV")]
|
|
||||||
NoType,
|
|
||||||
#[error ("Unrecognized TLV type")]
|
|
||||||
UnrecognizedType,
|
|
||||||
}
|
|
||||||
|
|
||||||
const MAGIC: [u8; 4] = [55, 11, 101, 38];
|
|
||||||
|
|
||||||
pub fn decode (src: &[u8]) -> Result <Message, Error>
|
|
||||||
{
|
|
||||||
let (magic, src) = take_bytes (src, 4).ok_or (Error::BadMagic)?;
|
|
||||||
if magic != MAGIC {
|
|
||||||
return Err (Error::BadMagic);
|
|
||||||
}
|
|
||||||
|
|
||||||
let (msg_type, src) = take_bytes(src, 1).ok_or(Error::NoType)?;
|
|
||||||
|
|
||||||
Ok (match msg_type [0] {
|
|
||||||
1 => {
|
|
||||||
let (peer_id, src) = take_u32 (src).ok_or (Error::MissingField)?;
|
|
||||||
Message::IAmOnline { peer_id, }
|
|
||||||
},
|
|
||||||
2 => {
|
|
||||||
let (peer_id, src) = take_u32 (src).ok_or (Error::MissingField)?;
|
|
||||||
let (msg_index, src) = take_u32 (src).ok_or (Error::MissingField)?;
|
|
||||||
let (body_len, src) = take_u32 (src).ok_or (Error::MissingField)?;
|
|
||||||
let (body_bytes, src) = take_bytes(src, body_len as usize).ok_or(Error::MissingField)?;
|
|
||||||
let body = body_bytes.into ();
|
|
||||||
Message::IHaveMessage { peer_id, msg_index, body, }
|
|
||||||
},
|
|
||||||
3 => {
|
|
||||||
let (msg_index, src) = take_u32 (src).ok_or (Error::MissingField)?;
|
|
||||||
Message::IAcknowledgeYourMessage { msg_index, }
|
|
||||||
},
|
|
||||||
_ => return Err (Error::UnrecognizedType),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_u32 (src: &[u8]) -> Option <(u32, &[u8])>
|
|
||||||
{
|
|
||||||
let (a, b) = take_bytes (src, 4)?;
|
|
||||||
Some ((u32::from_le_bytes([a [0], a [1], a [2], a [3]]), b))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn take_bytes (src: &[u8], n: usize) -> Option <(&[u8], &[u8])>
|
|
||||||
{
|
|
||||||
if src.len () < n {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some (src.split_at (n))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn encode (msg: &Message) -> Result <Vec <u8>, Error>
|
|
||||||
{
|
|
||||||
let mut buf = Vec::from (MAGIC);
|
|
||||||
|
|
||||||
match msg {
|
|
||||||
Message::IAmOnline { peer_id } => {
|
|
||||||
buf.push (1);
|
|
||||||
buf.extend_from_slice (&peer_id.to_le_bytes());
|
|
||||||
},
|
|
||||||
Message::IHaveMessage { peer_id, msg_index, body } => {
|
|
||||||
buf.push (2);
|
|
||||||
buf.extend_from_slice (&peer_id.to_le_bytes());
|
|
||||||
buf.extend_from_slice (&msg_index.to_le_bytes());
|
|
||||||
|
|
||||||
let body_len = u32::try_from (body.len ()).or (Err (Error::DataTooBig))?;
|
|
||||||
buf.extend_from_slice (&body_len.to_le_bytes());
|
|
||||||
buf.extend_from_slice(body.as_slice());
|
|
||||||
},
|
|
||||||
Message::IAcknowledgeYourMessage { msg_index } => {
|
|
||||||
buf.push (3);
|
|
||||||
buf.extend_from_slice (&msg_index.to_le_bytes());
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok (buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg (test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn roundtrip () {
|
|
||||||
for msg in [
|
|
||||||
Message::IAmOnline { peer_id: 93 },
|
|
||||||
Message::IHaveMessage { peer_id: 93, msg_index: 1000, body: Vec::from (b":V".as_slice()) },
|
|
||||||
Message::IAcknowledgeYourMessage { msg_index: 1000 },
|
|
||||||
] {
|
|
||||||
let encoded = encode (&msg).unwrap ();
|
|
||||||
let roundtripped = decode (&encoded).unwrap ();
|
|
||||||
assert_eq!(roundtripped, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -31,7 +31,6 @@ use ptth_core::{
|
||||||
use ptth_server::{
|
use ptth_server::{
|
||||||
file_server::{
|
file_server::{
|
||||||
self,
|
self,
|
||||||
metrics,
|
|
||||||
FileServer,
|
FileServer,
|
||||||
},
|
},
|
||||||
load_toml,
|
load_toml,
|
||||||
|
|
|
@ -26,10 +26,10 @@ async fn main () -> anyhow::Result <()> {
|
||||||
tokio::fs::write ("ptth_quic_output/quic_server.crt", app.server_cert ()).await?;
|
tokio::fs::write ("ptth_quic_output/quic_server.crt", app.server_cert ()).await?;
|
||||||
|
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
val = app.run () => {
|
_val = app.run () => {
|
||||||
|
|
||||||
},
|
},
|
||||||
val = running_rx.changed () => {
|
_val = running_rx.changed () => {
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,8 +109,6 @@ pub struct Relay {
|
||||||
#[derive (Clone, Default)]
|
#[derive (Clone, Default)]
|
||||||
pub (crate) struct MonitoringCounters {
|
pub (crate) struct MonitoringCounters {
|
||||||
pub (crate) requests_total: u64,
|
pub (crate) requests_total: u64,
|
||||||
pub (crate) requests_by_scraper_api: HashMap <String, u64>,
|
|
||||||
pub (crate) requests_by_email: HashMap <String, u64>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive (Clone)]
|
#[derive (Clone)]
|
||||||
|
@ -122,7 +120,6 @@ pub struct RejectedServer {
|
||||||
|
|
||||||
#[derive (Clone, Debug)]
|
#[derive (Clone, Debug)]
|
||||||
pub struct AuditEvent {
|
pub struct AuditEvent {
|
||||||
time_monotonic: Instant,
|
|
||||||
pub time_utc: DateTime <Utc>,
|
pub time_utc: DateTime <Utc>,
|
||||||
pub data: AuditData,
|
pub data: AuditData,
|
||||||
}
|
}
|
||||||
|
@ -148,7 +145,6 @@ pub enum AuditData {
|
||||||
impl AuditEvent {
|
impl AuditEvent {
|
||||||
pub fn new (data: AuditData) -> Self {
|
pub fn new (data: AuditData) -> Self {
|
||||||
Self {
|
Self {
|
||||||
time_monotonic: Instant::now (),
|
|
||||||
time_utc: Utc::now (),
|
time_utc: Utc::now (),
|
||||||
data,
|
data,
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,7 @@ async fn api_v1 (
|
||||||
})).await;
|
})).await;
|
||||||
|
|
||||||
if path_rest == "metrics" {
|
if path_rest == "metrics" {
|
||||||
Ok (metrics (req, state).await?)
|
Ok (metrics (state).await?)
|
||||||
}
|
}
|
||||||
else if path_rest == "test" {
|
else if path_rest == "test" {
|
||||||
Ok (error_reply (StatusCode::OK, "You're valid!")?)
|
Ok (error_reply (StatusCode::OK, "You're valid!")?)
|
||||||
|
@ -223,9 +223,8 @@ async fn api_v1 (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument (level = "trace", skip (req, state))]
|
#[instrument (level = "trace", skip (state))]
|
||||||
async fn metrics (
|
async fn metrics (
|
||||||
req: Request <Body>,
|
|
||||||
state: &Relay,
|
state: &Relay,
|
||||||
)
|
)
|
||||||
-> Result <Response <Body>, RequestError>
|
-> Result <Response <Body>, RequestError>
|
||||||
|
|
|
@ -57,7 +57,7 @@ pub async fn handle_listen (
|
||||||
|
|
||||||
let mut server_status = state.server_status.lock ().await;
|
let mut server_status = state.server_status.lock ().await;
|
||||||
|
|
||||||
let mut status = server_status.entry (watcher_code.clone ()).or_insert_with (Default::default);
|
let status = server_status.entry (watcher_code.clone ()).or_insert_with (Default::default);
|
||||||
|
|
||||||
status.last_seen = now;
|
status.last_seen = now;
|
||||||
}
|
}
|
||||||
|
|
|
@ -419,27 +419,6 @@ impl FileServer {
|
||||||
send_body,
|
send_body,
|
||||||
range,
|
range,
|
||||||
}) => serve_file (uri, file.into_inner (), send_body, range, headers.get ("if-none-match").map (|v| &v[..])).await?,
|
}) => serve_file (uri, file.into_inner (), send_body, range, headers.get ("if-none-match").map (|v| &v[..])).await?,
|
||||||
MarkdownErr (e) => {
|
|
||||||
#[cfg (feature = "markdown")]
|
|
||||||
{
|
|
||||||
use markdown::Error::*;
|
|
||||||
let e = e.inner;
|
|
||||||
let code = match &e {
|
|
||||||
TooBig => StatusCode::InternalServerError,
|
|
||||||
//NotMarkdown => serve_error (StatusCode::BadRequest, "File is not Markdown"),
|
|
||||||
NotUtf8 => StatusCode::BadRequest,
|
|
||||||
};
|
|
||||||
|
|
||||||
return Ok (serve_error (code, e.to_string ()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg (not (feature = "markdown"))]
|
|
||||||
{
|
|
||||||
let _e = e;
|
|
||||||
serve_error (StatusCode::BadRequest, "Markdown feature is disabled")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MarkdownPreview (s) => html::serve (s),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,9 +76,6 @@ pub enum Response {
|
||||||
Root,
|
Root,
|
||||||
ServeDir (ServeDirParams),
|
ServeDir (ServeDirParams),
|
||||||
ServeFile (ServeFileParams),
|
ServeFile (ServeFileParams),
|
||||||
|
|
||||||
MarkdownErr (MarkdownErrWrapper),
|
|
||||||
MarkdownPreview (String),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg (feature = "markdown")]
|
#[cfg (feature = "markdown")]
|
||||||
|
@ -131,7 +128,7 @@ fn serve_dir (
|
||||||
|
|
||||||
async fn serve_file (
|
async fn serve_file (
|
||||||
file: tokio::fs::File,
|
file: tokio::fs::File,
|
||||||
uri: &http::Uri,
|
_uri: &http::Uri,
|
||||||
send_body: bool,
|
send_body: bool,
|
||||||
headers: &HashMap <String, Vec <u8>>
|
headers: &HashMap <String, Vec <u8>>
|
||||||
)
|
)
|
||||||
|
|
|
@ -266,8 +266,6 @@ pub struct Config {
|
||||||
|
|
||||||
pub struct Builder {
|
pub struct Builder {
|
||||||
config_file: ConfigFile,
|
config_file: ConfigFile,
|
||||||
hidden_path: Option <PathBuf>,
|
|
||||||
asset_root: Option <PathBuf>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Builder {
|
impl Builder {
|
||||||
|
@ -289,17 +287,13 @@ impl Builder {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
config_file,
|
config_file,
|
||||||
hidden_path: None,
|
|
||||||
asset_root: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build (self) -> Result <State, ServerError>
|
pub fn build (self) -> Result <State, ServerError>
|
||||||
{
|
{
|
||||||
State::new (
|
State::new (
|
||||||
self.config_file,
|
self.config_file
|
||||||
self.hidden_path,
|
|
||||||
self.asset_root
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,12 +334,8 @@ pub async fn run_server (
|
||||||
|
|
||||||
let state = Arc::new (State::new (
|
let state = Arc::new (State::new (
|
||||||
config_file,
|
config_file,
|
||||||
hidden_path,
|
|
||||||
asset_root,
|
|
||||||
)?);
|
)?);
|
||||||
|
|
||||||
let file_server_2 = Arc::clone (&file_server);
|
|
||||||
|
|
||||||
let mut spawn_handler = || {
|
let mut spawn_handler = || {
|
||||||
let file_server = Arc::clone (&file_server);
|
let file_server = Arc::clone (&file_server);
|
||||||
let hit_counter = hit_counter.clone ();
|
let hit_counter = hit_counter.clone ();
|
||||||
|
@ -353,7 +343,7 @@ pub async fn run_server (
|
||||||
|req: http_serde::RequestParts| async move {
|
|req: http_serde::RequestParts| async move {
|
||||||
if let Some (hit_tx) = &hit_counter {
|
if let Some (hit_tx) = &hit_counter {
|
||||||
eprintln! ("hit_tx.send");
|
eprintln! ("hit_tx.send");
|
||||||
hit_tx.send (()).await;
|
hit_tx.send (()).await.ok ();
|
||||||
}
|
}
|
||||||
Ok (file_server.serve_all (req.method, &req.uri, &req.headers).await?)
|
Ok (file_server.serve_all (req.method, &req.uri, &req.headers).await?)
|
||||||
}
|
}
|
||||||
|
@ -369,15 +359,11 @@ pub async fn run_server (
|
||||||
impl State {
|
impl State {
|
||||||
pub fn new (
|
pub fn new (
|
||||||
config_file: ConfigFile,
|
config_file: ConfigFile,
|
||||||
hidden_path: Option <PathBuf>,
|
|
||||||
asset_root: Option <PathBuf>
|
|
||||||
)
|
)
|
||||||
-> Result <Self, ServerError>
|
-> Result <Self, ServerError>
|
||||||
{
|
{
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
let asset_root = asset_root.unwrap_or_else (PathBuf::new);
|
|
||||||
|
|
||||||
info! ("Server name is {}", config_file.name);
|
info! ("Server name is {}", config_file.name);
|
||||||
info! ("Tripcode is {}", config_file.tripcode ());
|
info! ("Tripcode is {}", config_file.tripcode ());
|
||||||
|
|
||||||
|
|
|
@ -24,18 +24,6 @@ fn load_inner <
|
||||||
Ok (toml::from_str (&config_s)?)
|
Ok (toml::from_str (&config_s)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For files that contain public-viewable information
|
|
||||||
|
|
||||||
fn load_public <
|
|
||||||
T: DeserializeOwned,
|
|
||||||
P: AsRef <Path> + Debug
|
|
||||||
> (
|
|
||||||
config_file_path: P
|
|
||||||
) -> Result <T, LoadTomlError> {
|
|
||||||
let f = File::open (&config_file_path)?;
|
|
||||||
load_inner (f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// For files that may contain secrets and should have permissions or other
|
/// For files that may contain secrets and should have permissions or other
|
||||||
/// safeties checked
|
/// safeties checked
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue