From f625dc23ebd346b4ab0999ef1e019a060681101e Mon Sep 17 00:00:00 2001 From: ghassmo Date: Fri, 29 Apr 2022 18:33:48 +0300 Subject: [PATCH] ircd: irc server support tls protocol --- Cargo.lock | 2 + bin/ircd/Cargo.toml | 2 + bin/ircd/ircd_config.toml | 2 +- bin/ircd/src/main.rs | 100 ++++++++++++++++++++++++++------------ bin/ircd/src/server.rs | 7 ++- bin/ircd/src/settings.rs | 4 +- src/net3/mod.rs | 2 +- 7 files changed, 81 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4be8184c..4c55a5f38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2266,6 +2266,7 @@ dependencies = [ "darkfi", "easy-parallel", "futures", + "futures-rustls", "fxhash", "log", "rand", @@ -2275,6 +2276,7 @@ dependencies = [ "smol", "structopt", "structopt-toml", + "url", ] [[package]] diff --git a/bin/ircd/Cargo.toml b/bin/ircd/Cargo.toml index 6d4b5caf3..08e7863a4 100644 --- a/bin/ircd/Cargo.toml +++ b/bin/ircd/Cargo.toml @@ -13,6 +13,7 @@ darkfi = {path = "../../", features = ["net", "rpc", "raft"]} # Async smol = "1.2.5" futures = "0.3.21" +futures-rustls = "0.22.1" async-std = "1.11.0" async-trait = "0.1.53" async-channel = "1.6.1" @@ -28,6 +29,7 @@ log = "0.4.16" simplelog = "0.12.0-alpha1" fxhash = "0.2.1" ctrlc-async = {version= "3.2.2", default-features = false, features = ["async-std", "termination"]} +url = "2.2.2" # Encoding and parsing serde_json = "1.0.79" diff --git a/bin/ircd/ircd_config.toml b/bin/ircd/ircd_config.toml index ce76ac486..325b46da7 100644 --- a/bin/ircd/ircd_config.toml +++ b/bin/ircd/ircd_config.toml @@ -2,7 +2,7 @@ #rpc_listen="127.0.0.1:11055" ## IRC listen URL -#irc_listen="127.0.0.1:11066" +#irc_listen="tcp://127.0.0.1:11066" ## Sets Datastore Path #datastore="~/.config/ircd" diff --git a/bin/ircd/src/main.rs b/bin/ircd/src/main.rs index db2e4614d..e33fb2ea0 100644 --- a/bin/ircd/src/main.rs +++ b/bin/ircd/src/main.rs @@ -1,13 +1,24 @@ use async_std::{ - net::{TcpListener, TcpStream}, + net::TcpStream, sync::{Arc, Mutex}, }; use std::net::SocketAddr; use async_channel::{Receiver, Sender}; use async_executor::Executor; +use easy_parallel::Parallel; +use futures::{ + io::BufReader, AsyncBufReadExt, AsyncRead, AsyncReadExt, AsyncWrite, FutureExt, StreamExt, +}; +use futures_rustls::TlsStream; +use log::{debug, error, info, warn}; +use simplelog::{ColorChoice, TermLogger, TerminalMode}; +use smol::future; +use structopt_toml::StructOptToml; + use darkfi::{ async_daemonize, + net::transport::{TcpTransport, TlsTransport, Transport}, raft::Raft, rpc::rpcserver::{listen_and_serve, RpcServerConfig}, util::{ @@ -16,12 +27,6 @@ use darkfi::{ }, Error, Result, }; -use easy_parallel::Parallel; -use futures::{io::BufReader, AsyncBufReadExt, AsyncReadExt, FutureExt}; -use log::{debug, error, info, warn}; -use simplelog::{ColorChoice, TermLogger, TerminalMode}; -use smol::future; -use structopt_toml::StructOptToml; pub mod privmsg; pub mod rpc; @@ -35,6 +40,12 @@ use crate::{ settings::{Args, CONFIG_FILE, CONFIG_FILE_CONTENTS}, }; +// TODO should using Stream from net3 instead +pub trait Stream: AsyncWrite + AsyncRead + Unpin + Send + Sync {} + +impl Stream for TcpStream {} +impl Stream for TlsStream {} + pub type SeenMsgIds = Arc>>; fn build_irc_msg(msg: &Privmsg) -> String { @@ -79,7 +90,7 @@ async fn broadcast_msg( async fn process( raft_receiver: Receiver, - stream: TcpStream, + stream: Box, peer_addr: SocketAddr, raft_sender: Sender, seen_msg_id: SeenMsgIds, @@ -98,7 +109,7 @@ async fn process( let mut smi = seen_msg_id.lock().await; if smi.contains(&msg.id) { - continue + continue } smi.push(msg.id); drop(smi); @@ -124,10 +135,6 @@ async fn process( async_daemonize!(realmain); async fn realmain(settings: Args, executor: Arc>) -> Result<()> { - let listener = TcpListener::bind(settings.irc_listen).await?; - let local_addr = listener.local_addr()?; - info!("IRC listening on {}", local_addr); - let seen_msg_id: SeenMsgIds = Arc::new(Mutex::new(vec![])); // @@ -160,27 +167,60 @@ async fn realmain(settings: Args, executor: Arc>) -> Result<()> { // let executor_cloned = executor.clone(); let irc_task: smol::Task> = executor.spawn(async move { - loop { - let (stream, peer_addr) = match listener.accept().await { - Ok((s, a)) => (s, a), - Err(e) => { - error!("Failed listening for connections: {}", e); - return Err(Error::ServiceStopped) + let irc_listen_url = url::Url::parse(&settings.irc_listen)?; + + match irc_listen_url.scheme() { + "tcp" => { + let transport = TcpTransport::new(None, 1024); + let listener = transport.listen_on(irc_listen_url.clone()).unwrap().await.unwrap(); + let mut incoming = listener.incoming(); + info!("IRC start a TCP connection {}", &irc_listen_url.to_string()); + while let Some(stream) = incoming.next().await { + let stream = stream.unwrap(); + let peer_addr = stream.peer_addr()?; + info!("IRC Accepted TCP connection {}", peer_addr); + executor_cloned + .spawn(process( + raft_receiver.clone(), + Box::new(stream), + peer_addr, + raft_sender.clone(), + seen_msg_id.clone(), + )) + .detach(); } - }; + } - info!("IRC Accepted client: {}", peer_addr); + "tls" => { + let transport = TlsTransport::new(None, 1024); + let (acceptor, listener) = + transport.listen_on(irc_listen_url.clone()).unwrap().await.unwrap(); + let mut incoming = listener.incoming(); + info!("IRC bind a TLS connection {}", &irc_listen_url.to_string()); + while let Some(stream) = incoming.next().await { + let stream = stream.unwrap(); + let peer_addr = stream.peer_addr()?; + info!("IRC Accepted TLS connection {}", peer_addr); + let stream = acceptor.accept(stream).await?; + executor_cloned + .spawn(process( + raft_receiver.clone(), + Box::new(TlsStream::Server(stream)), + peer_addr, + raft_sender.clone(), + seen_msg_id.clone(), + )) + .detach(); + } + } - executor_cloned - .spawn(process( - raft_receiver.clone(), - stream, - peer_addr, - raft_sender.clone(), - seen_msg_id.clone(), - )) - .detach(); + x => { + error!("Transport protocol '{}' isn't implemented", x); + return Err(Error::UnsupportedTransport(x.to_string())) + } } + + Ok(()) }); let (signal, shutdown) = async_channel::bounded::<()>(1); diff --git a/bin/ircd/src/server.rs b/bin/ircd/src/server.rs index 5b0c5cc29..e2ccef94e 100644 --- a/bin/ircd/src/server.rs +++ b/bin/ircd/src/server.rs @@ -1,14 +1,13 @@ -use async_std::net::TcpStream; use futures::{io::WriteHalf, AsyncWriteExt}; use log::{debug, info, warn}; use rand::{rngs::OsRng, RngCore}; use darkfi::{Error, Result}; -use crate::{privmsg::Privmsg, SeenMsgIds}; +use crate::{privmsg::Privmsg, SeenMsgIds, Stream}; pub struct IrcServerConnection { - write_stream: WriteHalf, + write_stream: WriteHalf>, is_nick_init: bool, is_user_init: bool, is_registered: bool, @@ -20,7 +19,7 @@ pub struct IrcServerConnection { impl IrcServerConnection { pub fn new( - write_stream: WriteHalf, + write_stream: WriteHalf>, seen_msg_id: SeenMsgIds, p2p_sender: async_channel::Sender, ) -> Self { diff --git a/bin/ircd/src/settings.rs b/bin/ircd/src/settings.rs index a86d94474..d5464a350 100644 --- a/bin/ircd/src/settings.rs +++ b/bin/ircd/src/settings.rs @@ -21,8 +21,8 @@ pub struct Args { #[structopt(long = "rpc", default_value = "127.0.0.1:11055")] pub rpc_listen: SocketAddr, /// IRC listen URL - #[structopt(long = "irc", default_value = "127.0.0.1:11066")] - pub irc_listen: SocketAddr, + #[structopt(long = "irc", default_value = "tcp://127.0.0.1:11066")] + pub irc_listen: String, /// Sets Datastore Path #[structopt(long, default_value = "~/.config/ircd")] pub datastore: String, diff --git a/src/net3/mod.rs b/src/net3/mod.rs index 894b69053..843a44fd8 100644 --- a/src/net3/mod.rs +++ b/src/net3/mod.rs @@ -89,7 +89,7 @@ pub mod settings; pub mod transport; pub use acceptor::{Acceptor, AcceptorPtr}; -pub use channel::{Channel, ChannelPtr}; +pub use channel::{Channel, ChannelPtr, Stream}; pub use connector::Connector; pub use hosts::{Hosts, HostsPtr}; pub use message::Message;