server.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. use std::net::SocketAddr;
  2. use futures::{io::WriteHalf, AsyncRead, AsyncWrite, AsyncWriteExt};
  3. use fxhash::FxHashMap;
  4. use log::{debug, info, warn};
  5. use rand::{rngs::OsRng, RngCore};
  6. use ringbuffer::{RingBufferExt, RingBufferWrite};
  7. use darkfi::{net::P2pPtr, system::SubscriberPtr, Error, Result};
  8. use crate::{
  9. crypto::{encrypt_message, try_decrypt_message},
  10. privmsg::{Privmsg, PrivmsgsBuffer, SeenMsgIds},
  11. ChannelInfo, MAXIMUM_LENGTH_OF_MESSAGE, MAXIMUM_LENGTH_OF_NICKNAME,
  12. };
  13. const RPL_NOTOPIC: u32 = 331;
  14. const RPL_TOPIC: u32 = 332;
  15. const RPL_NAMEREPLY: u32 = 353;
  16. const RPL_ENDOFNAMES: u32 = 366;
  17. pub struct IrcServerConnection<C: AsyncRead + AsyncWrite + Send + Unpin + 'static> {
  18. // server stream
  19. write_stream: WriteHalf<C>,
  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. is_cap_end: bool,
  29. nickname: String,
  30. auto_channels: Vec<String>,
  31. pub configured_chans: FxHashMap<String, ChannelInfo>,
  32. capabilities: FxHashMap<String, bool>,
  33. // p2p
  34. p2p: P2pPtr,
  35. senders: SubscriberPtr<Privmsg>,
  36. subscriber_id: u64,
  37. }
  38. impl<C: AsyncRead + AsyncWrite + Send + Unpin + 'static> IrcServerConnection<C> {
  39. #[allow(clippy::too_many_arguments)]
  40. pub fn new(
  41. write_stream: WriteHalf<C>,
  42. peer_address: SocketAddr,
  43. seen_msg_ids: SeenMsgIds,
  44. privmsgs_buffer: PrivmsgsBuffer,
  45. auto_channels: Vec<String>,
  46. configured_chans: FxHashMap<String, ChannelInfo>,
  47. p2p: P2pPtr,
  48. senders: SubscriberPtr<Privmsg>,
  49. subscriber_id: u64,
  50. ) -> Self {
  51. let mut capabilities = FxHashMap::default();
  52. capabilities.insert("no-history".to_string(), false);
  53. Self {
  54. write_stream,
  55. peer_address,
  56. seen_msg_ids,
  57. privmsgs_buffer,
  58. is_nick_init: false,
  59. is_user_init: false,
  60. is_registered: false,
  61. is_cap_end: true,
  62. nickname: "anon".to_string(),
  63. auto_channels,
  64. configured_chans,
  65. capabilities,
  66. p2p,
  67. senders,
  68. subscriber_id,
  69. }
  70. }
  71. async fn update(&mut self, line: String) -> Result<()> {
  72. if line.len() > MAXIMUM_LENGTH_OF_MESSAGE {
  73. return Err(Error::MalformedPacket)
  74. }
  75. let mut tokens = line.split_ascii_whitespace();
  76. // Commands can begin with :garbage but we will reject clients doing
  77. // that for now to keep the protocol simple and focused.
  78. let command = tokens.next().ok_or(Error::MalformedPacket)?;
  79. info!("IRC server received command: {}", command.to_uppercase());
  80. match command.to_uppercase().as_str() {
  81. "USER" => {
  82. // We can stuff any extra things like public keys in here.
  83. // Ignore it for now.
  84. self.is_user_init = true;
  85. }
  86. "NAMES" => {
  87. let channels = tokens.next().ok_or(Error::MalformedPacket)?;
  88. for chan in channels.split(',') {
  89. if !chan.starts_with('#') {
  90. warn!("{} is not a valid name for channel", chan);
  91. continue
  92. }
  93. self.on_receive_names(chan).await?;
  94. }
  95. }
  96. "NICK" => {
  97. let nickname = tokens.next().ok_or(Error::MalformedPacket)?;
  98. if nickname.len() > MAXIMUM_LENGTH_OF_NICKNAME {
  99. return Ok(())
  100. }
  101. self.is_nick_init = true;
  102. let old_nick = std::mem::replace(&mut self.nickname, nickname.to_string());
  103. let nick_reply = format!(":{}!anon@dark.fi NICK {}\r\n", old_nick, self.nickname);
  104. self.reply(&nick_reply).await?;
  105. }
  106. "JOIN" => {
  107. let channels = tokens.next().ok_or(Error::MalformedPacket)?;
  108. for chan in channels.split(',') {
  109. if !chan.starts_with('#') {
  110. warn!("{} is not a valid name for channel", chan);
  111. continue
  112. }
  113. self.on_join(chan).await?;
  114. }
  115. }
  116. "PART" => {
  117. let channels = tokens.next().ok_or(Error::MalformedPacket)?;
  118. for chan in channels.split(',') {
  119. let part_reply = format!(":{}!anon@dark.fi PART {}\r\n", self.nickname, chan);
  120. self.reply(&part_reply).await?;
  121. if self.configured_chans.contains_key(chan) {
  122. let chan_info = self.configured_chans.get_mut(chan).unwrap();
  123. chan_info.joined = false;
  124. }
  125. }
  126. }
  127. "TOPIC" => {
  128. let channel = tokens.next().ok_or(Error::MalformedPacket)?;
  129. if let Some(substr_idx) = line.find(':') {
  130. // Client is setting the topic
  131. if substr_idx >= line.len() {
  132. return Err(Error::MalformedPacket)
  133. }
  134. let topic = &line[substr_idx + 1..];
  135. let chan_info = self.configured_chans.get_mut(channel).unwrap();
  136. chan_info.topic = Some(topic.to_string());
  137. let topic_reply =
  138. format!(":{}!anon@dark.fi TOPIC {} :{}\r\n", self.nickname, channel, topic);
  139. self.reply(&topic_reply).await?;
  140. } else {
  141. // Client is asking or the topic
  142. let chan_info = self.configured_chans.get(channel).unwrap();
  143. let topic_reply = if let Some(topic) = &chan_info.topic {
  144. format!("{} {} {} :{}\r\n", RPL_TOPIC, self.nickname, channel, topic)
  145. } else {
  146. const TOPIC: &str = "No topic is set";
  147. format!("{} {} {} :{}\r\n", RPL_NOTOPIC, self.nickname, channel, TOPIC)
  148. };
  149. self.reply(&topic_reply).await?;
  150. }
  151. }
  152. "PING" => {
  153. let pong = tokens.next().ok_or(Error::MalformedPacket)?;
  154. let pong = format!("PONG {}\r\n", pong);
  155. self.reply(&pong).await?;
  156. }
  157. "PRIVMSG" => {
  158. let target = tokens.next().ok_or(Error::MalformedPacket)?;
  159. let substr_idx = line.find(':').ok_or(Error::MalformedPacket)?;
  160. if substr_idx >= line.len() {
  161. return Err(Error::MalformedPacket)
  162. }
  163. let mut message = line[substr_idx + 1..].to_string();
  164. info!("(Plain) PRIVMSG {} :{}", target, message);
  165. if target.starts_with("#") {
  166. if !self.configured_chans.contains_key(target) {
  167. return Ok(())
  168. }
  169. let channel_info = self.configured_chans.get(target).unwrap();
  170. if !channel_info.joined {
  171. return Ok(())
  172. }
  173. message = if let Some(salt_box) = &channel_info.salt_box {
  174. let encrypted = encrypt_message(salt_box, &message);
  175. info!("(Encrypted) PRIVMSG {} :{}", target, encrypted);
  176. encrypted
  177. } else {
  178. message.to_string()
  179. };
  180. }
  181. self.on_receive_privmsg(&message, target).await?;
  182. }
  183. "CAP" => {
  184. self.is_cap_end = false;
  185. let subcommand = tokens.next().ok_or(Error::MalformedPacket)?.to_uppercase();
  186. let capabilities_keys: Vec<String> = self.capabilities.keys().cloned().collect();
  187. if subcommand == "LS" {
  188. let cap_ls_reply = format!(
  189. ":{}!anon@dark.fi CAP * LS :{}\r\n",
  190. self.nickname,
  191. capabilities_keys.join(" ")
  192. );
  193. self.reply(&cap_ls_reply).await?;
  194. }
  195. if subcommand == "REQ" {
  196. let substr_idx = line.find(':').ok_or(Error::MalformedPacket)?;
  197. if substr_idx >= line.len() {
  198. return Err(Error::MalformedPacket)
  199. }
  200. let cap: Vec<&str> = line[substr_idx + 1..].split(" ").collect();
  201. let mut ack_list = vec![];
  202. let mut nak_list = vec![];
  203. for c in cap {
  204. if self.capabilities.contains_key(c) {
  205. self.capabilities.insert(c.to_string(), true);
  206. ack_list.push(c);
  207. } else {
  208. nak_list.push(c);
  209. }
  210. }
  211. let cap_ack_reply = format!(
  212. ":{}!anon@dark.fi CAP * ACK :{}\r\n",
  213. self.nickname,
  214. ack_list.join(" ")
  215. );
  216. let cap_nak_reply = format!(
  217. ":{}!anon@dark.fi CAP * NAK :{}\r\n",
  218. self.nickname,
  219. nak_list.join(" ")
  220. );
  221. self.reply(&cap_ack_reply).await?;
  222. self.reply(&cap_nak_reply).await?;
  223. }
  224. if subcommand == "LIST" {
  225. let enabled_capabilities: Vec<String> = self
  226. .capabilities
  227. .clone()
  228. .into_iter()
  229. .filter(|(_, v)| *v)
  230. .map(|(k, _)| k)
  231. .collect();
  232. let cap_list_reply = format!(
  233. ":{}!anon@dark.fi CAP * LIST :{}\r\n",
  234. self.nickname,
  235. enabled_capabilities.join(" ")
  236. );
  237. self.reply(&cap_list_reply).await?;
  238. }
  239. if subcommand == "END" {
  240. self.is_cap_end = true;
  241. }
  242. }
  243. "QUIT" => {
  244. // Close the connection
  245. return Err(Error::NetworkServiceStopped)
  246. }
  247. _ => {
  248. warn!("Unimplemented `{}` command", command);
  249. }
  250. }
  251. // on registration
  252. if !self.is_registered && self.is_cap_end && self.is_nick_init && self.is_user_init {
  253. debug!("Initializing peer connection");
  254. let register_reply = format!(":darkfi 001 {} :Let there be dark\r\n", self.nickname);
  255. self.reply(&register_reply).await?;
  256. self.is_registered = true;
  257. for chan in self.auto_channels.clone() {
  258. self.on_join(&chan).await?;
  259. }
  260. // Send dm messages in buffer
  261. if *self.capabilities.get("no-history").unwrap() {
  262. return Ok(())
  263. }
  264. for msg in self.privmsgs_buffer.lock().await.to_vec() {
  265. if msg.target == self.nickname ||
  266. (msg.nickname == self.nickname && !msg.target.starts_with("#"))
  267. {
  268. self.senders.notify_by_id(msg, self.subscriber_id).await;
  269. }
  270. }
  271. }
  272. Ok(())
  273. }
  274. async fn reply(&mut self, message: &str) -> Result<()> {
  275. self.write_stream.write_all(message.as_bytes()).await?;
  276. debug!("Sent {}", message);
  277. Ok(())
  278. }
  279. async fn on_receive_names(&mut self, chan: &str) -> Result<()> {
  280. if self.configured_chans.contains_key(chan) {
  281. let chan_info = self.configured_chans.get(chan).unwrap();
  282. if chan_info.names.is_empty() {
  283. return Ok(())
  284. }
  285. let names_reply = format!(
  286. ":{}!anon@dark.fi {} = {} : {}\r\n",
  287. self.nickname,
  288. RPL_NAMEREPLY,
  289. chan,
  290. chan_info.names.join(" ")
  291. );
  292. self.reply(&names_reply).await?;
  293. let end_of_names = format!(
  294. ":DarkFi {:03} {} {} :End of NAMES list\r\n",
  295. RPL_ENDOFNAMES, self.nickname, chan
  296. );
  297. self.reply(&end_of_names).await?;
  298. }
  299. Ok(())
  300. }
  301. async fn on_receive_privmsg(&mut self, message: &str, target: &str) -> Result<()> {
  302. let random_id = OsRng.next_u64();
  303. let protocol_msg = Privmsg {
  304. id: random_id,
  305. nickname: self.nickname.clone(),
  306. target: target.to_string(),
  307. message: message.to_string(),
  308. };
  309. {
  310. (*self.seen_msg_ids.lock().await).push(random_id);
  311. (*self.privmsgs_buffer.lock().await).push(protocol_msg.clone())
  312. }
  313. self.senders.notify_with_exclude(protocol_msg.clone(), &[self.subscriber_id]).await;
  314. debug!(target: "ircd", "PRIVMSG to be sent: {:?}", protocol_msg);
  315. self.p2p.broadcast(protocol_msg).await?;
  316. Ok(())
  317. }
  318. async fn on_join(&mut self, chan: &str) -> Result<()> {
  319. if !self.configured_chans.contains_key(chan) {
  320. let mut chan_info = ChannelInfo::new()?;
  321. chan_info.topic = Some("n/a".to_string());
  322. self.configured_chans.insert(chan.to_string(), chan_info);
  323. }
  324. let chan_info = self.configured_chans.get_mut(chan).unwrap();
  325. if chan_info.joined {
  326. return Ok(())
  327. }
  328. chan_info.joined = true;
  329. let topic =
  330. if let Some(topic) = chan_info.topic.clone() { topic } else { "n/a".to_string() };
  331. chan_info.topic = Some(topic.to_string());
  332. {
  333. let j = format!(":{}!anon@dark.fi JOIN {}\r\n", self.nickname, chan);
  334. let t = format!(":DarkFi TOPIC {} :{}\r\n", chan, topic);
  335. self.reply(&j).await?;
  336. self.reply(&t).await?;
  337. }
  338. // Send messages in buffer
  339. if !self.capabilities.get("no-history").unwrap() {
  340. for msg in self.privmsgs_buffer.lock().await.to_vec() {
  341. if msg.target == chan {
  342. self.senders.notify_by_id(msg, self.subscriber_id).await;
  343. }
  344. }
  345. }
  346. self.on_receive_names(chan).await?;
  347. Ok(())
  348. }
  349. pub async fn process_msg_from_p2p(&mut self, msg: &Privmsg) -> Result<()> {
  350. info!("Received msg from P2p network: {:?}", msg);
  351. let mut msg = msg.clone();
  352. if msg.target.starts_with("#") {
  353. // Try to potentially decrypt the incoming message.
  354. if !self.configured_chans.contains_key(&msg.target) {
  355. return Ok(())
  356. }
  357. let chan_info = self.configured_chans.get_mut(&msg.target).unwrap();
  358. if !chan_info.joined {
  359. return Ok(())
  360. }
  361. let salt_box = chan_info.salt_box.clone();
  362. if salt_box.is_some() {
  363. let decrypted_msg = try_decrypt_message(&salt_box.unwrap(), &msg.message);
  364. if decrypted_msg.is_none() {
  365. return Ok(())
  366. }
  367. msg.message = decrypted_msg.unwrap();
  368. info!("Decrypted received message: {:?}", msg);
  369. }
  370. // add the nickname to the channel's names
  371. if !chan_info.names.contains(&msg.nickname) {
  372. chan_info.names.push(msg.nickname.clone());
  373. }
  374. self.reply(&msg.to_irc_msg()).await?;
  375. return Ok(())
  376. }
  377. if self.is_cap_end &&
  378. self.is_nick_init &&
  379. (self.nickname == msg.target || self.nickname == msg.nickname)
  380. {
  381. self.reply(&msg.to_irc_msg()).await?;
  382. }
  383. Ok(())
  384. }
  385. pub async fn process_line_from_client(
  386. &mut self,
  387. err: std::result::Result<usize, std::io::Error>,
  388. line: String,
  389. ) -> Result<()> {
  390. if let Err(e) = err {
  391. warn!("Read line error {}: {}", self.peer_address, e);
  392. return Err(Error::ChannelStopped)
  393. }
  394. info!("Received msg from IRC client: {:?}", line);
  395. let irc_msg = self.clean_input_line(line)?;
  396. if let Err(e) = self.update(irc_msg).await {
  397. warn!("Connection error: {} for {}", e, self.peer_address);
  398. return Err(Error::ChannelStopped)
  399. }
  400. Ok(())
  401. }
  402. fn clean_input_line(&self, mut line: String) -> Result<String> {
  403. if line.is_empty() {
  404. warn!("Received empty line from {}. ", self.peer_address);
  405. warn!("Closing connection.");
  406. return Err(Error::ChannelStopped)
  407. }
  408. if &line[(line.len() - 2)..] == "\r\n" {
  409. // Remove CRLF
  410. line.pop();
  411. line.pop();
  412. } else if &line[(line.len() - 1)..] == "\n" {
  413. line.pop();
  414. } else {
  415. warn!("Closing connection.");
  416. return Err(Error::ChannelStopped)
  417. }
  418. Ok(line.clone())
  419. }
  420. }