server.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. use async_std::net::TcpStream;
  2. use std::net::SocketAddr;
  3. use futures::{io::WriteHalf, AsyncWriteExt};
  4. use fxhash::FxHashMap;
  5. use log::{debug, info, warn};
  6. use rand::{rngs::OsRng, RngCore};
  7. use ringbuffer::{RingBufferExt, RingBufferWrite};
  8. use darkfi::{net::P2pPtr, system::SubscriberPtr, Error, Result};
  9. use crate::{
  10. crypto::{encrypt_message, try_decrypt_message},
  11. privmsg::{Privmsg, PrivmsgsBuffer, SeenMsgIds},
  12. ChannelInfo,
  13. };
  14. const RPL_NOTOPIC: u32 = 331;
  15. const RPL_TOPIC: u32 = 332;
  16. const RPL_NAMEREPLY: u32 = 353;
  17. pub struct IrcServerConnection {
  18. // server stream
  19. write_stream: WriteHalf<TcpStream>,
  20. peer_address: SocketAddr,
  21. // msg ids
  22. seen_msg_ids: SeenMsgIds,
  23. privmsgs_buffer: PrivmsgsBuffer,
  24. // user & channels
  25. is_nick_init: bool,
  26. is_user_init: bool,
  27. is_registered: bool,
  28. nickname: String,
  29. auto_channels: Vec<String>,
  30. pub configured_chans: FxHashMap<String, ChannelInfo>,
  31. // p2p
  32. p2p: P2pPtr,
  33. senders: SubscriberPtr<Privmsg>,
  34. subscriber_id: u64,
  35. }
  36. impl IrcServerConnection {
  37. pub fn new(
  38. write_stream: WriteHalf<TcpStream>,
  39. peer_address: SocketAddr,
  40. seen_msg_ids: SeenMsgIds,
  41. privmsgs_buffer: PrivmsgsBuffer,
  42. auto_channels: Vec<String>,
  43. configured_chans: FxHashMap<String, ChannelInfo>,
  44. p2p: P2pPtr,
  45. senders: SubscriberPtr<Privmsg>,
  46. subscriber_id: u64,
  47. ) -> Self {
  48. Self {
  49. write_stream,
  50. peer_address,
  51. seen_msg_ids,
  52. privmsgs_buffer,
  53. is_nick_init: false,
  54. is_user_init: false,
  55. is_registered: false,
  56. nickname: "anon".to_string(),
  57. auto_channels,
  58. configured_chans,
  59. p2p,
  60. senders,
  61. subscriber_id,
  62. }
  63. }
  64. async fn update(&mut self, line: String) -> Result<()> {
  65. if line.len() > 513 {
  66. return Err(Error::MalformedPacket)
  67. }
  68. let mut tokens = line.split_ascii_whitespace();
  69. // Commands can begin with :garbage but we will reject clients doing
  70. // that for now to keep the protocol simple and focused.
  71. let command = tokens.next().ok_or(Error::MalformedPacket)?;
  72. info!("IRC server received command: {}", command.to_uppercase());
  73. match command.to_uppercase().as_str() {
  74. "USER" => {
  75. // We can stuff any extra things like public keys in here.
  76. // Ignore it for now.
  77. self.is_user_init = true;
  78. }
  79. "NAMES" => {
  80. let channels = tokens.next().ok_or(Error::MalformedPacket)?;
  81. for chan in channels.split(',') {
  82. if !chan.starts_with('#') {
  83. warn!("{} is not a valid name for channel", chan);
  84. continue
  85. }
  86. if self.configured_chans.contains_key(chan) {
  87. let chan_info = self.configured_chans.get(chan).unwrap();
  88. if chan_info.names.is_empty() {
  89. continue
  90. }
  91. let names_reply = format!(
  92. ":{}!anon@dark.fi {} = {} : {}\r\n",
  93. self.nickname,
  94. RPL_NAMEREPLY,
  95. chan,
  96. chan_info.names.join(" ")
  97. );
  98. self.reply(&names_reply).await?;
  99. }
  100. }
  101. }
  102. "NICK" => {
  103. let nickname = tokens.next().ok_or(Error::MalformedPacket)?;
  104. if nickname.len() > 10 {
  105. return Ok(())
  106. }
  107. self.is_nick_init = true;
  108. let old_nick = std::mem::replace(&mut self.nickname, nickname.to_string());
  109. let nick_reply = format!(":{}!anon@dark.fi NICK {}\r\n", old_nick, self.nickname);
  110. self.reply(&nick_reply).await?;
  111. }
  112. "JOIN" => {
  113. let channels = tokens.next().ok_or(Error::MalformedPacket)?;
  114. for chan in channels.split(',') {
  115. if !chan.starts_with('#') {
  116. warn!("{} is not a valid name for channel", chan);
  117. continue
  118. }
  119. let join_reply = format!(":{}!anon@dark.fi JOIN {}\r\n", self.nickname, chan);
  120. self.reply(&join_reply).await?;
  121. if !self.configured_chans.contains_key(chan) {
  122. self.configured_chans.insert(chan.to_string(), ChannelInfo::new()?);
  123. } else {
  124. let chan_info = self.configured_chans.get_mut(chan).unwrap();
  125. chan_info.joined = true;
  126. }
  127. // Send messages in buffer
  128. for msg in self.privmsgs_buffer.lock().await.to_vec() {
  129. if msg.channel == chan {
  130. self.senders.notify_by_id(msg, self.subscriber_id).await;
  131. }
  132. }
  133. }
  134. }
  135. "PART" => {
  136. let channels = tokens.next().ok_or(Error::MalformedPacket)?;
  137. for chan in channels.split(',') {
  138. let part_reply = format!(":{}!anon@dark.fi PART {}\r\n", self.nickname, chan);
  139. self.reply(&part_reply).await?;
  140. if self.configured_chans.contains_key(chan) {
  141. let chan_info = self.configured_chans.get_mut(chan).unwrap();
  142. chan_info.joined = false;
  143. }
  144. }
  145. }
  146. "TOPIC" => {
  147. let channel = tokens.next().ok_or(Error::MalformedPacket)?;
  148. if let Some(substr_idx) = line.find(':') {
  149. // Client is setting the topic
  150. if substr_idx >= line.len() {
  151. return Err(Error::MalformedPacket)
  152. }
  153. let topic = &line[substr_idx + 1..];
  154. let chan_info = self.configured_chans.get_mut(channel).unwrap();
  155. chan_info.topic = Some(topic.to_string());
  156. let topic_reply =
  157. format!(":{}!anon@dark.fi TOPIC {} :{}\r\n", self.nickname, channel, topic);
  158. self.reply(&topic_reply).await?;
  159. } else {
  160. // Client is asking or the topic
  161. let chan_info = self.configured_chans.get(channel).unwrap();
  162. let topic_reply = if let Some(topic) = &chan_info.topic {
  163. format!("{} {} {} :{}\r\n", RPL_TOPIC, self.nickname, channel, topic)
  164. } else {
  165. const TOPIC: &str = "No topic is set";
  166. format!("{} {} {} :{}\r\n", RPL_NOTOPIC, self.nickname, channel, TOPIC)
  167. };
  168. self.reply(&topic_reply).await?;
  169. }
  170. }
  171. "PING" => {
  172. let pong = tokens.next().ok_or(Error::MalformedPacket)?;
  173. let pong = format!("PONG {}\r\n", pong);
  174. self.reply(&pong).await?;
  175. }
  176. "PRIVMSG" => {
  177. let channel = tokens.next().ok_or(Error::MalformedPacket)?;
  178. let substr_idx = line.find(':').ok_or(Error::MalformedPacket)?;
  179. if substr_idx >= line.len() {
  180. return Err(Error::MalformedPacket)
  181. }
  182. let message = &line[substr_idx + 1..];
  183. info!("(Plain) PRIVMSG {} :{}", channel, message);
  184. if self.configured_chans.contains_key(channel) {
  185. let channel_info = self.configured_chans.get(channel).unwrap();
  186. if channel_info.joined {
  187. let message = if let Some(salt_box) = &channel_info.salt_box {
  188. let encrypted = encrypt_message(salt_box, message);
  189. info!("(Encrypted) PRIVMSG {} :{}", channel, encrypted);
  190. encrypted
  191. } else {
  192. message.to_string()
  193. };
  194. let random_id = OsRng.next_u64();
  195. let protocol_msg = Privmsg {
  196. id: random_id,
  197. nickname: self.nickname.clone(),
  198. channel: channel.to_string(),
  199. message,
  200. };
  201. {
  202. (*self.seen_msg_ids.lock().await).push(random_id);
  203. (*self.privmsgs_buffer.lock().await).push(protocol_msg.clone())
  204. }
  205. self.senders
  206. .notify_with_exclude(protocol_msg.clone(), &[self.subscriber_id])
  207. .await;
  208. debug!(target: "ircd", "PRIVMSG to be sent: {:?}", protocol_msg);
  209. self.p2p.broadcast(protocol_msg).await?;
  210. }
  211. }
  212. }
  213. "QUIT" => {
  214. // Close the connection
  215. return Err(Error::NetworkServiceStopped)
  216. }
  217. _ => {
  218. warn!("Unimplemented `{}` command", command);
  219. }
  220. }
  221. if !self.is_registered && self.is_nick_init && self.is_user_init {
  222. debug!("Initializing peer connection");
  223. let register_reply = format!(":darkfi 001 {} :Let there be dark\r\n", self.nickname);
  224. self.reply(&register_reply).await?;
  225. self.is_registered = true;
  226. // Auto-joins
  227. macro_rules! autojoin {
  228. ($channel:expr,$topic:expr) => {
  229. let j = format!(":{}!anon@dark.fi JOIN {}\r\n", self.nickname, $channel);
  230. let t = format!(":DarkFi TOPIC {} :{}\r\n", $channel, $topic);
  231. self.reply(&j).await?;
  232. self.reply(&t).await?;
  233. };
  234. }
  235. for chan in self.auto_channels.clone() {
  236. if self.configured_chans.contains_key(&chan) {
  237. let chan_info = self.configured_chans.get_mut(&chan).unwrap();
  238. let topic = if let Some(topic) = chan_info.topic.clone() {
  239. topic
  240. } else {
  241. "n/a".to_string()
  242. };
  243. chan_info.topic = Some(topic.to_string());
  244. autojoin!(chan, topic);
  245. } else {
  246. let mut chan_info = ChannelInfo::new()?;
  247. chan_info.topic = Some("n/a".to_string());
  248. self.configured_chans.insert(chan.clone(), chan_info);
  249. autojoin!(chan, "n/a");
  250. }
  251. }
  252. }
  253. Ok(())
  254. }
  255. pub async fn reply(&mut self, message: &str) -> Result<()> {
  256. self.write_stream.write_all(message.as_bytes()).await?;
  257. debug!("Sent {}", message);
  258. Ok(())
  259. }
  260. pub async fn process_msg_from_p2p(&mut self, msg: &Privmsg) -> Result<()> {
  261. let mut msg = msg.clone();
  262. // Try to potentially decrypt the incoming message.
  263. if self.configured_chans.contains_key(&msg.channel) {
  264. let chan_info = self.configured_chans.get_mut(&msg.channel).unwrap();
  265. if !chan_info.joined {
  266. return Ok(())
  267. }
  268. let salt_box = chan_info.salt_box.clone();
  269. if salt_box.is_some() {
  270. let decrypted_msg = try_decrypt_message(&salt_box.unwrap(), &msg.message);
  271. if decrypted_msg.is_none() {
  272. return Ok(())
  273. }
  274. msg.message = decrypted_msg.unwrap();
  275. info!("Decrypted received message: {:?}", msg);
  276. }
  277. // add the nickname to the channel's names
  278. if !chan_info.names.contains(&msg.nickname) {
  279. chan_info.names.push(msg.nickname.clone());
  280. }
  281. }
  282. self.reply(&msg.to_irc_msg()).await?;
  283. Ok(())
  284. }
  285. pub async fn process_line_from_client(
  286. &mut self,
  287. err: std::result::Result<usize, std::io::Error>,
  288. line: String,
  289. ) -> Result<()> {
  290. if let Err(e) = err {
  291. warn!("Read line error {}: {}", self.peer_address, e);
  292. return Err(Error::ChannelStopped)
  293. }
  294. info!("Received msg from IRC client: {:?}", line);
  295. let irc_msg = self.clean_input_line(line)?;
  296. info!("Send msg to IRC client '{}' from {}", irc_msg, self.peer_address);
  297. if let Err(e) = self.update(irc_msg).await {
  298. warn!("Connection error: {} for {}", e, self.peer_address);
  299. return Err(Error::ChannelStopped)
  300. }
  301. Ok(())
  302. }
  303. fn clean_input_line(&self, mut line: String) -> Result<String> {
  304. if line.is_empty() {
  305. warn!("Received empty line from {}. ", self.peer_address);
  306. warn!("Closing connection.");
  307. return Err(Error::ChannelStopped)
  308. }
  309. if &line[(line.len() - 2)..] == "\r\n" {
  310. // Remove CRLF
  311. line.pop();
  312. line.pop();
  313. } else if &line[(line.len() - 1)..] == "\n" {
  314. line.pop();
  315. } else {
  316. warn!("Closing connection.");
  317. return Err(Error::ChannelStopped)
  318. }
  319. Ok(line.clone())
  320. }
  321. }