1use crate::{
2 auth::TorAuthentication,
3 error::TorError,
4 key::{TorEd25519SigningKey, TorServiceId},
5};
6use futures::{SinkExt, StreamExt};
7use lazy_static::lazy_static;
8use log::info;
9use regex::{Captures, Regex};
10use serde::{Deserialize, Serialize};
11use std::fmt::{Display, Error, Formatter};
12use std::net::{AddrParseError, SocketAddr as TcpSocketAddr};
13use std::os::unix::net::SocketAddr as UnixSocketAddr;
14use std::path::Path;
15use std::pin::Pin;
16use std::str::FromStr;
17use std::task::{Context, Poll};
18use tokio::{
19 io::{AsyncRead, AsyncWrite, ReadBuf, ReadHalf, WriteHalf},
20 net::{TcpListener, TcpStream, ToSocketAddrs, UnixListener, UnixStream},
21};
22use tokio_util::codec::{FramedRead, FramedWrite, LinesCodec, LinesCodecError};
23
24#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Deserialize, Serialize)]
28pub enum TorSocketAddr {
29 Tcp(TcpSocketAddr),
30 Unix(String),
31}
32
33impl TorSocketAddr {
34 fn from_tcp_string(address: &str) -> Result<Self, AddrParseError> {
36 Ok(Self::Tcp(TcpSocketAddr::from_str(address)?))
37 }
38
39 fn from_unix_string<P: AsRef<Path>>(path: P) -> Result<Self, std::io::Error> {
41 Ok(Self::Unix(
42 UnixSocketAddr::from_pathname(path)?
43 .as_pathname()
44 .unwrap()
45 .to_str()
46 .unwrap()
47 .to_string(),
48 ))
49 }
50}
51
52impl From<TcpSocketAddr> for TorSocketAddr {
54 fn from(socket_addr: TcpSocketAddr) -> Self {
55 Self::Tcp(socket_addr)
56 }
57}
58
59impl Display for TorSocketAddr {
60 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
61 match self {
62 Self::Tcp(sock_addr) => write!(f, "{}", sock_addr),
63 Self::Unix(sock_addr) => write!(f, "unix:{:?}", sock_addr),
64 }
65 }
66}
67
68#[derive(Debug)]
70pub enum ListenAddressParseError {
71 TcpParseError(AddrParseError),
72 UnixParseError(std::io::Error),
73}
74
75impl std::error::Error for ListenAddressParseError {}
76
77impl Display for ListenAddressParseError {
78 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
79 match self {
80 Self::TcpParseError(error) => write!(f, "Error parsing TCP address: {}", error),
81 Self::UnixParseError(error) => write!(f, "Error parsing Unix address:{}", error),
82 }
83 }
84}
85
86impl From<AddrParseError> for ListenAddressParseError {
87 fn from(err: AddrParseError) -> Self {
88 Self::TcpParseError(err)
89 }
90}
91
92impl From<std::io::Error> for ListenAddressParseError {
93 fn from(err: std::io::Error) -> Self {
94 Self::UnixParseError(err)
95 }
96}
97
98impl FromStr for TorSocketAddr {
99 type Err = ListenAddressParseError;
100
101 fn from_str(s: &str) -> Result<Self, Self::Err> {
102 if let Some(path) = s.strip_prefix("unix:") {
103 Ok(Self::from_unix_string(path)?)
104 } else {
105 Ok(Self::from_tcp_string(s)?)
106 }
107 }
108}
109
110pub enum OnionServiceListener {
112 Tcp(TcpListener),
113 Unix(UnixListener),
114}
115
116impl OnionServiceListener {
117 pub async fn bind(socket_addr: TorSocketAddr) -> Result<OnionServiceListener, std::io::Error> {
119 match socket_addr {
120 TorSocketAddr::Tcp(socket_addr) => Ok(OnionServiceListener::Tcp(
121 TcpListener::bind(socket_addr).await?,
122 )),
123 TorSocketAddr::Unix(path) => Ok(OnionServiceListener::Unix(UnixListener::bind(path)?)),
124 }
125 }
126
127 pub async fn accept(&self) -> Result<(OnionServiceStream, TorSocketAddr), std::io::Error> {
129 match self {
130 Self::Tcp(listener) => {
131 let (stream, socket) = listener.accept().await?;
132 Ok((OnionServiceStream::Tcp(stream), socket.into()))
133 }
134 Self::Unix(listener) => {
135 let (stream, socket) = listener.accept().await?;
136 Ok((
137 OnionServiceStream::Unix(stream),
138 TorSocketAddr::Unix(
139 socket.as_pathname().unwrap().to_string_lossy().to_string(),
140 ),
141 ))
142 }
143 }
144 }
145}
146
147pub enum OnionServiceStream {
149 Tcp(TcpStream),
150 Unix(UnixStream),
151}
152
153impl AsyncRead for OnionServiceStream {
154 fn poll_read(
155 self: Pin<&mut Self>,
156 cx: &mut Context<'_>,
157 buf: &mut ReadBuf<'_>,
158 ) -> Poll<Result<(), std::io::Error>> {
159 match Pin::into_inner(self) {
160 Self::Tcp(stream) => Pin::new(stream).poll_read(cx, buf),
161 Self::Unix(stream) => Pin::new(stream).poll_read(cx, buf),
162 }
163 }
164}
165
166impl AsyncWrite for OnionServiceStream {
167 fn poll_write(
168 self: Pin<&mut Self>,
169 cx: &mut Context<'_>,
170 buf: &[u8],
171 ) -> Poll<Result<usize, std::io::Error>> {
172 match Pin::into_inner(self) {
173 Self::Tcp(stream) => Pin::new(stream).poll_write(cx, buf),
174 Self::Unix(stream) => Pin::new(stream).poll_write(cx, buf),
175 }
176 }
177
178 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>> {
179 match Pin::into_inner(self) {
180 Self::Tcp(stream) => Pin::new(stream).poll_flush(cx),
181 Self::Unix(stream) => Pin::new(stream).poll_flush(cx),
182 }
183 }
184
185 fn poll_shutdown(
186 self: Pin<&mut Self>,
187 cx: &mut Context<'_>,
188 ) -> Poll<Result<(), std::io::Error>> {
189 match Pin::into_inner(self) {
190 Self::Tcp(stream) => Pin::new(stream).poll_shutdown(cx),
191 Self::Unix(stream) => Pin::new(stream).poll_shutdown(cx),
192 }
193 }
194}
195
196#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Deserialize, Serialize)]
198pub struct OnionServiceMapping {
199 virt_port: u16,
200 listen_address: TorSocketAddr,
201}
202
203impl OnionServiceMapping {
204 pub fn new(virt_port: u16, listen_address: Option<TorSocketAddr>) -> Self {
205 Self {
206 virt_port,
207 listen_address: match listen_address {
208 None => {
209 TorSocketAddr::from_tcp_string(&format!("127.0.0.1:{}", virt_port)).unwrap()
210 }
211 Some(a) => a,
212 },
213 }
214 }
215
216 pub fn virt_port(&self) -> u16 {
217 self.virt_port
218 }
219
220 pub fn listen_address(&self) -> &TorSocketAddr {
221 &self.listen_address
222 }
223}
224
225#[derive(Clone, Debug, Eq, PartialEq)]
227pub struct OnionAddress {
228 service_id: TorServiceId,
229 service_port: u16,
230}
231
232impl OnionAddress {
233 pub fn new(service_id: TorServiceId, port: u16) -> Self {
234 Self {
235 service_id,
236 service_port: port,
237 }
238 }
239
240 pub fn service_id(&self) -> &TorServiceId {
241 &self.service_id
242 }
243
244 pub fn service_port(&self) -> u16 {
245 self.service_port
246 }
247}
248
249impl FromStr for OnionAddress {
250 type Err = TorError;
251
252 fn from_str(s: &str) -> Result<Self, Self::Err> {
253 let values = s.split(':').collect::<Vec<&str>>();
254 if values.len() != 2 {
255 return Err(TorError::protocol_error("Bad onion address"));
256 }
257 let host_values = values[0].split('.').collect::<Vec<&str>>();
258 if host_values.len() != 2 || host_values[1] != "onion" {
259 return Err(TorError::protocol_error("Bad onion address"));
260 }
261 let service_id = match TorServiceId::from_str(host_values[0]) {
262 Ok(id) => id,
263 Err(error) => {
264 return Err(TorError::protocol_error(&format!(
265 "Error parsing host field in onion address: {}",
266 error
267 )));
268 }
269 };
270 let service_port = match values[1].parse::<u16>() {
271 Ok(port) => port,
272 Err(error) => {
273 return Err(TorError::protocol_error(&format!(
274 "Error parsing port field in onion address: {}",
275 error
276 )));
277 }
278 };
279 Ok(Self {
280 service_id,
281 service_port,
282 })
283 }
284}
285
286impl Display for OnionAddress {
287 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
288 write!(f, "{}.onion:{}", self.service_id, self.service_port)
289 }
290}
291
292#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Deserialize, Serialize)]
307pub struct OnionService {
308 ports: Vec<OnionServiceMapping>,
309 service_id: TorServiceId,
310 signing_key: TorEd25519SigningKey,
311}
312
313impl OnionService {
314 pub fn new<S, K>(id: S, key: K, ports: &[OnionServiceMapping]) -> Self
316 where
317 TorServiceId: From<S>,
318 TorEd25519SigningKey: From<K>,
319 {
320 Self {
321 ports: ports.to_vec(),
322 service_id: id.into(),
323 signing_key: key.into(),
324 }
325 }
326
327 pub fn listen_addresses_for_onion_address(&self, onion_address: &str) -> Vec<TorSocketAddr> {
331 self.ports
332 .iter()
333 .map(|p| (p, format!("{}.onion:{}", self.service_id, p.virt_port)))
334 .filter(|(_p, a)| a == onion_address)
335 .map(|(p, _a)| p.listen_address.clone())
336 .collect()
337 }
338
339 pub fn listen_addresses_for_port(&self, service_port: u16) -> Vec<TorSocketAddr> {
341 self.ports
342 .iter()
343 .filter(|p| p.virt_port == service_port)
344 .map(|p| p.listen_address.clone())
345 .collect()
346 }
347
348 pub fn onion_address(&self, service_port: u16) -> Result<OnionAddress, TorError> {
351 if self.ports.iter().any(|p| p.virt_port == service_port) {
352 Ok(OnionAddress {
353 service_id: self.service_id.clone(),
354 service_port,
355 })
356 } else {
357 Err(TorError::protocol_error(&format!(
358 "No Onion Service Port {} found for onion service {}",
359 service_port, self.service_id
360 )))
361 }
362 }
363
364 pub fn onion_addresses(&self) -> Vec<OnionAddress> {
366 self.ports
367 .iter()
368 .map(|p| OnionAddress::new(self.service_id.clone(), p.virt_port))
369 .collect()
370 }
371
372 pub fn service_id(&self) -> &TorServiceId {
374 &self.service_id
375 }
376
377 pub fn signing_key(&self) -> &TorEd25519SigningKey {
379 &self.signing_key
380 }
381
382 pub fn ports(&self) -> &Vec<OnionServiceMapping> {
384 &self.ports
385 }
386}
387
388#[derive(Debug)]
390pub struct ControlResponse {
391 pub status_code: u16,
392 pub reply: String,
393}
394
395impl ControlResponse {
396 fn new() -> Self {
397 Self {
398 status_code: 0,
399 reply: String::new(),
400 }
401 }
402}
403
404fn parse_status_code(code_str: &str) -> Result<u16, TorError> {
405 match code_str.parse::<u16>() {
406 Ok(status_code) => Ok(status_code),
407 Err(error) => Err(TorError::protocol_error(&format!(
408 "Error parsing response status code: {}",
409 error
410 ))),
411 }
412}
413
414async fn read_control_response<S: StreamExt<Item = Result<String, LinesCodecError>> + Unpin>(
416 reader: &mut S,
417) -> Result<ControlResponse, TorError> {
418 lazy_static! {
419 static ref MID_REGEX: Regex = Regex::new(r"^(?P<code>\d{3})-(?P<reply_line>.*)$").unwrap();
421
422 static ref DATA_REGEX: Regex =
424 Regex::new(r"^(?P<code>\d{3})\+(?P<reply_line>.*)$").unwrap();
425
426 static ref END_REGEX: Regex = Regex::new(r"^(?P<code>\d{3}) (?P<reply_line>.*)$").unwrap();
428 }
429
430 let mut control_response = ControlResponse::new();
431 loop {
432 let mut line = read_line(reader).await?;
433 info!("<= {}", line);
434 match MID_REGEX.captures(&line) {
435 Some(captures) => {
437 control_response.status_code = parse_status_code(&captures["code"])?;
438 control_response
439 .reply
440 .push_str(&format!("{}\n", &captures["reply_line"]));
441 }
442 None => match DATA_REGEX.captures(&line.clone()) {
443 Some(captures) => {
445 control_response.status_code = parse_status_code(&captures["code"])?;
446 let mut reply_line = captures["reply_line"].to_string();
447 reply_line.push('\n');
448 loop {
449 line = read_line(reader).await?;
450 if line == "." {
451 break;
452 }
453 reply_line.push_str(&line);
454 reply_line.push('\n');
455 }
456 control_response.reply = reply_line;
457 read_line(reader).await?;
459 return Ok(control_response);
460 }
461 None => match END_REGEX.captures(&line) {
462 Some(captures) => {
463 control_response.status_code = parse_status_code(&captures["code"])?;
464 if control_response.reply.is_empty() {
466 control_response.reply.push_str(&captures["reply_line"]);
467 }
468 return Ok(control_response);
469 }
470 None => {
471 return Err(TorError::ProtocolError(format!(
472 "Unknown response: {}",
473 line
474 )))
475 }
476 },
477 },
478 }
479 }
480}
481
482async fn read_line<S: StreamExt<Item = Result<String, LinesCodecError>> + Unpin>(
484 reader: &mut S,
485) -> Result<String, TorError> {
486 match reader.next().await {
487 Some(Ok(line)) => Ok(line),
488 Some(Err(error)) => Err(error.into()),
489 None => Err(TorError::protocol_error("Unexpected EOF on stream")),
490 }
491}
492
493fn format_onion_service_request_string(
495 key_type: &str,
496 key_blob: &str,
497 ports: &[OnionServiceMapping],
498 transient: bool,
499) -> String {
500 let flags = if transient { "" } else { "Flags=Detach" };
501 let port_string = ports
502 .iter()
503 .map(|p| format!("Port={},{}", p.virt_port, p.listen_address))
504 .collect::<Vec<String>>()
505 .join(" ");
506 format!("{}:{} {} {}", key_type, key_blob, flags, port_string)
507}
508
509fn format_key_request_string(
510 ports: &[OnionServiceMapping],
511 transient: bool,
512 signing_key: Option<&TorEd25519SigningKey>,
513) -> String {
514 match signing_key {
515 Some(signing_key) => format_onion_service_request_string(
516 "ED25519-V3",
517 &signing_key.to_blob(),
518 ports,
519 transient,
520 ),
521 None => format_onion_service_request_string("NEW", "BEST", ports, transient),
522 }
523}
524
525fn parse_required_response_field<'a>(
527 captures: &Captures<'a>,
528 field_name: &str,
529 field_arg: &str,
530 response_type: &str,
531) -> Result<&'a str, TorError> {
532 match captures.name(field_name) {
533 Some(field) => Ok(field.as_str()),
534 None => Err(TorError::protocol_error(&format!(
535 "'{}' field not found in {} response",
536 field_arg, response_type,
537 ))),
538 }
539}
540
541fn parse_add_onion_response(
542 captures: &Captures<'_>,
543 ports: &[OnionServiceMapping],
544 signing_key: Option<&TorEd25519SigningKey>,
545) -> Result<OnionService, TorError> {
546 let hash_string =
548 parse_required_response_field(captures, "service_id", "ServiceID", "ADD_ONION")?;
549
550 let (returned_signing_key, verifying_key) = match signing_key {
553 Some(signing_key) => (signing_key.clone(), signing_key.verifying_key()),
554 None => match captures.name("key_type") {
555 Some(_) => {
556 let signing_key =
557 TorEd25519SigningKey::from_blob(captures.name("key_blob").unwrap().as_str());
558 let verifying_key = signing_key.verifying_key();
559 (signing_key, verifying_key)
560 }
561 None => {
562 return Err(TorError::protocol_error(
563 "Expected signing key to be returned by Tor",
564 ));
565 }
566 },
567 };
568
569 let expected_service_id: TorServiceId = verifying_key.into();
570
571 if expected_service_id.as_str() != hash_string {
572 return Err(
573 TorError::protocol_error(&format!(
574 "Service ID for onion service returned by tor ({}) doesn't match the service ID generated from verifying key ({})",
575 hash_string, expected_service_id.as_str())));
576 }
577
578 let service_id = match TorServiceId::from_str(hash_string) {
579 Ok(id) => id,
580 Err(error) => {
581 return Err(TorError::protocol_error(&format!(
582 "Error parsing Tor Service ID: {}",
583 error
584 )))
585 }
586 };
587
588 Ok(OnionService::new(service_id, returned_signing_key, ports))
590}
591
592#[derive(Clone, Debug)]
595pub struct ProtocolInfo {
596 pub auth_methods: Vec<String>,
597 pub cookie_file: Option<String>,
598 pub tor_version: String,
599}
600
601pub struct TorControlConnection {
604 reader: FramedRead<ReadHalf<TcpStream>, LinesCodec>,
605 writer: FramedWrite<WriteHalf<TcpStream>, LinesCodec>,
606 protocol_info: Option<ProtocolInfo>,
607}
608
609impl TorControlConnection {
610 pub async fn connect<A: ToSocketAddrs>(addrs: A) -> Result<Self, TorError> {
612 let this = Self::with_stream(TcpStream::connect(addrs).await?)?;
613 Ok(this)
614 }
615
616 pub(crate) fn with_stream(stream: TcpStream) -> Result<Self, TorError> {
618 let (reader, writer) = tokio::io::split(stream);
619 Ok(Self {
620 reader: FramedRead::new(reader, LinesCodec::new()),
621 writer: FramedWrite::new(writer, LinesCodec::new()),
622 protocol_info: None,
623 })
624 }
625
626 async fn write(&mut self, data: &str) -> Result<(), TorError> {
628 self.writer.send(data).await?;
629 Ok(())
630 }
631
632 pub async fn get_protocol_info(&mut self) -> Result<ProtocolInfo, TorError> {
634 if self.protocol_info.is_some() {
635 Ok(self.protocol_info.clone().unwrap())
636 } else {
637 let control_response = self.send_command("PROTOCOLINFO", Some("1")).await?;
638
639 if control_response.status_code != 250 {
640 return Err(TorError::protocol_error(&format!(
641 "Expected status code 250, got {}",
642 control_response.status_code
643 )));
644 }
645
646 lazy_static! {
648 static ref RE: Regex =
649 Regex::new(r"^PROTOCOLINFO 1\nAUTH METHODS=(?P<auth_methods>[^ ]*)( COOKIEFILE=(?P<cookie_file>.*))*\nVERSION Tor=(?P<tor_version>.*)\n")
650 .unwrap();
651 }
652 let captures = match RE.captures(&control_response.reply) {
653 Some(captures) => captures,
654 None => {
655 return Err(TorError::protocol_error(
656 "Error parsing PROTOCOLINFO response",
657 ))
658 }
659 };
660 let auth_methods = parse_required_response_field(
661 &captures,
662 "auth_methods",
663 "AUTH METHODS",
664 "PROTOCOLINFO",
665 )?
666 .split(',')
667 .map(|s| s.to_string())
668 .collect();
669 let tor_version =
670 parse_required_response_field(&captures, "tor_version", "VERSION", "PROTOCOLINFO")?
671 .replace('"', "");
672 let protocol_info = ProtocolInfo {
673 auth_methods,
674 cookie_file: captures
675 .name("cookie_file")
676 .map(|c| c.as_str().replace('"', "").to_string()),
677 tor_version,
678 };
679 self.protocol_info = Some(protocol_info.clone());
680 Ok(protocol_info)
681 }
682 }
683
684 pub async fn get_info(&mut self, info: &str) -> Result<Vec<String>, TorError> {
686 let control_response = self.send_command("GETINFO", Some(info)).await?;
687 info!(
688 "Send GETINFO command, got control response {:?}",
689 control_response
690 );
691 if control_response.status_code != 250 {
692 return Err(TorError::protocol_error(&format!(
693 "Expected status code 250, got {}",
694 control_response.status_code
695 )));
696 }
697 let split_response = &control_response
698 .reply
699 .trim_end()
700 .split('=')
701 .collect::<Vec<&str>>();
702 if split_response.len() <= 1 {
703 return Err(TorError::protocol_error(&format!(
704 "Got unexpected reply '{}', expected key/value pair",
705 control_response.reply
706 )));
707 }
708
709 let response = split_response[1].split('\n').collect::<Vec<&str>>();
710
711 let mut ret = Vec::new();
712 for value in response.iter() {
713 if !value.is_empty() {
714 ret.push(value.to_string());
715 }
716 }
717
718 Ok(ret)
719 }
720
721 pub async fn authenticate(&mut self, method: TorAuthentication) -> Result<(), TorError> {
723 method.authenticate(self).await?;
724 Ok(())
725 }
726
727 pub(crate) async fn send_command(
729 &mut self,
730 command: &str,
731 arguments: Option<&str>,
732 ) -> Result<ControlResponse, TorError> {
733 let command_string = match arguments {
734 None => command.to_string(),
735 Some(arguments) => format!("{} {}", command, arguments),
736 };
737 info!("=> {}", command_string);
738 self.write(&command_string).await?;
739 match read_control_response(&mut self.reader).await {
740 Ok(control_response) => match control_response.status_code {
741 250 | 251 => Ok(control_response),
742 _ => Err(TorError::ProtocolError(control_response.reply)),
743 },
744 Err(error) => Err(error),
745 }
746 }
747
748 pub async fn create_onion_service(
750 &mut self,
751 ports: &[OnionServiceMapping],
752 transient: bool,
753 signing_key: Option<&TorEd25519SigningKey>,
754 ) -> Result<OnionService, TorError> {
755 let request_string = format_key_request_string(ports, transient, signing_key);
757
758 let control_response = self
760 .send_command("ADD_ONION", Some(&request_string))
761 .await?;
762 info!(
763 "Sent ADD_ONION command, got control response {:?}",
764 control_response
765 );
766
767 if control_response.status_code != 250 {
768 return Err(TorError::protocol_error(&format!(
769 "Expected status code 250, got {}",
770 control_response.status_code
771 )));
772 }
773
774 lazy_static! {
776 static ref RE: Regex =
777 Regex::new(r"(?m)^ServiceID=(?P<service_id>.*)\n(PrivateKey=(?P<key_type>[^:]*):(?<key_blob>.*)$)?$")
778 .unwrap();
779 }
780 match RE.captures(&control_response.reply) {
781 Some(captures) => parse_add_onion_response(&captures, ports, signing_key),
782 None => Err(TorError::ProtocolError(format!(
783 "Unexpected response: {} {}",
784 control_response.status_code, control_response.reply,
785 ))),
786 }
787 }
788
789 pub async fn delete_onion_service(&mut self, service_id: &str) -> Result<(), TorError> {
790 let service_id_string = service_id.replace(".onion", "");
792
793 let control_response = self
795 .send_command("DEL_ONION", Some(&service_id_string))
796 .await?;
797 info!(
798 "Sent DEL_ONION command, got control response {:?}",
799 control_response
800 );
801
802 if control_response.status_code != 250 {
803 Err(TorError::protocol_error(&format!(
804 "Expected status code 250, got {}",
805 control_response.status_code
806 )))
807 } else {
808 Ok(())
809 }
810 }
811}
812
813#[cfg(test)]
814mod tests {
815 use super::*;
816 use futures::SinkExt;
817 use tokio;
818 use tokio::net::{TcpListener, TcpStream};
819 use tokio_util::codec::{Framed, LinesCodec};
820
821 async fn create_mock() -> Result<(TcpStream, TcpStream), Box<dyn std::error::Error>> {
822 let listener = TcpListener::bind("127.0.0.1:0").await?;
823 let addr = listener.local_addr()?;
824 let join_handle = tokio::spawn(async move { listener.accept().await.unwrap() });
825 let client = TcpStream::connect(addr).await?;
826 let (server_stream, _) = join_handle.await?;
827
828 Ok((client, server_stream))
829 }
830
831 async fn create_framed_mock() -> Result<
832 (Framed<TcpStream, LinesCodec>, Framed<TcpStream, LinesCodec>),
833 Box<dyn std::error::Error>,
834 > {
835 let (client, server) = create_mock().await?;
836 let reader = Framed::new(client, LinesCodec::new());
837 let server = Framed::new(server, LinesCodec::new());
838
839 Ok((reader, server))
840 }
841
842 #[tokio::test]
843 async fn test_read_good_control_response() -> Result<(), Box<dyn std::error::Error>> {
844 let (mut client, mut server) = create_framed_mock().await?;
846 server.send("250 OK").await?;
847 let result = read_control_response(&mut client).await;
848 assert!(result.is_ok());
849 let control_response = result.unwrap();
850 assert_eq!(250, control_response.status_code);
851 assert_eq!("OK", control_response.reply);
852
853 Ok(())
854 }
855
856 #[tokio::test]
857 async fn test_read_garbled_control_response() -> Result<(), Box<dyn std::error::Error>> {
858 let (mut client, mut server) = create_framed_mock().await?;
860 server.send("idon'tknowwhatthisis").await?;
861 let result = read_control_response(&mut client).await;
862 assert!(result.is_err());
863 match result.err() {
864 Some(TorError::ProtocolError(_)) => assert!(true),
865 _ => assert!(false),
866 }
867
868 let (mut client, mut server) = create_framed_mock().await?;
870 server
871 .send("250-ServiceID=647qjf6w3evdbdpy7oidf5vda6rsjzsl5a6ofsaou2v77hj7dmn2spqd")
872 .await?;
873 server.send("250-PrivateKey=ED25519-V3:yLSDc8b11PaIHTtNtvi9lNW99IME2mdrO4k381zDkHv//WRUGrkBALBQ9MbHy2SLA/NmfS7YxmcR/FY8ppRfIA==").await?;
874 server.send("250 OK").await?;
875 let result = read_control_response(&mut client).await;
876 assert!(result.is_ok());
877 let control_response = result.unwrap();
878 assert_eq!(250, control_response.status_code);
879 assert_eq!(
880 "ServiceID=647qjf6w3evdbdpy7oidf5vda6rsjzsl5a6ofsaou2v77hj7dmn2spqd\nPrivateKey=ED25519-V3:yLSDc8b11PaIHTtNtvi9lNW99IME2mdrO4k381zDkHv//WRUGrkBALBQ9MbHy2SLA/NmfS7YxmcR/FY8ppRfIA==\n",
881 control_response.reply);
882
883 Ok(())
884 }
885
886 #[tokio::test]
887 async fn test_read_data_control_response() -> Result<(), Box<dyn std::error::Error>> {
888 let (mut client, mut server) = create_framed_mock().await?;
890 server.send("250+onions/current=").await?;
891 server
892 .send("647qjf6w3evdbdpy7oidf5vda6rsjzsl5a6ofsaou2v77hj7dmn2spqd")
893 .await?;
894 server
895 .send("yxq7fa63tthq3nd2ul52jjcdpblyai6k3cfmdkyw23ljsoob66z3ywid")
896 .await?;
897 server.send(".").await?;
898 server.send("250 OK").await?;
899 let result = read_control_response(&mut client).await;
900 assert!(result.is_ok());
901 let control_response = result.unwrap();
902 assert_eq!(250, control_response.status_code);
903 assert_eq!("onions/current=\n647qjf6w3evdbdpy7oidf5vda6rsjzsl5a6ofsaou2v77hj7dmn2spqd\nyxq7fa63tthq3nd2ul52jjcdpblyai6k3cfmdkyw23ljsoob66z3ywid\n",
904 control_response.reply,
905 );
906
907 Ok(())
908 }
909
910 #[tokio::test]
911 async fn test_authenticate() -> Result<(), Box<dyn std::error::Error>> {
912 let (client, server) = create_mock().await?;
913 let mut server = Framed::new(server, LinesCodec::new());
914 server
915 .send("250-PROTOCOLINFO 1\n250-AUTH METHODS=NULL\n250-VERSION Tor=1\n250 OK")
916 .await?;
917 server.send("250 OK").await?;
918 let mut tor = TorControlConnection::with_stream(client)?;
919 let result = tor.authenticate(TorAuthentication::Null).await;
920 assert!(result.is_ok());
921
922 let (client, server) = create_mock().await?;
923 let mut server = Framed::new(server, LinesCodec::new());
924 server.send("551 Oops").await?;
925 let mut tor = TorControlConnection::with_stream(client)?;
926 let result = tor.authenticate(TorAuthentication::Null).await;
927 assert!(result.is_err());
928
929 Ok(())
930 }
931
932 #[tokio::test]
933 async fn test_create_onion_service() -> Result<(), Box<dyn std::error::Error>> {
934 let (client, server) = create_mock().await?;
935 let mut server = Framed::new(server, LinesCodec::new());
936 server
937 .send("250-ServiceID=vvqbbaknxi6w44t6rplzh7nmesfzw3rjujdijpqsu5xl3nhlkdscgqad")
938 .await?;
939 server
940 .send("250-PrivateKey=ED25519-V3:0H/jnBeWzMoU1MGNRQPnmd8JqlpTNS3UeTiDOMyPTGGXXpLd0KinCtQbcgz2fCYjbzfK3ElJ7x3zGCkB1fAtAA==")
941 .await?;
942 server.send("250 OK").await?;
943 let mut tor = TorControlConnection::with_stream(client)?;
944 let onion_service = tor
945 .create_onion_service(&[OnionServiceMapping::new(8080, None)], true, None)
946 .await?;
947 assert_eq!(8080, onion_service.ports[0].virt_port);
948 assert_eq!(
949 TorSocketAddr::from_tcp_string("127.0.0.1:8080"),
950 Ok(onion_service.ports[0].clone().listen_address)
951 );
952 assert_eq!(
953 "vvqbbaknxi6w44t6rplzh7nmesfzw3rjujdijpqsu5xl3nhlkdscgqad",
954 onion_service.service_id.as_str()
955 );
956 assert_eq!(
957 OnionAddress::from_str(
958 "vvqbbaknxi6w44t6rplzh7nmesfzw3rjujdijpqsu5xl3nhlkdscgqad.onion:8080"
959 )?,
960 onion_service.onion_address(8080).unwrap()
961 );
962 Ok(())
963 }
964
965 #[tokio::test]
966 async fn test_get_protocol_info() -> Result<(), Box<dyn std::error::Error>> {
967 let (client, server) = create_mock().await?;
968 let mut server = Framed::new(server, LinesCodec::new());
969 server.send("250-PROTOCOLINFO 1").await?;
970 server.send("250-AUTH METHODS=NULL,FOO").await?;
971 server.send("250-VERSION Tor=\"0.4.7.13\"").await?;
972 server.send("250 OK").await?;
973 let mut tor = TorControlConnection::with_stream(client)?;
974 tor.get_protocol_info().await?;
975
976 Ok(())
977 }
978
979 #[test]
980 fn test_parse_onion_address() -> Result<(), Box<dyn std::error::Error>> {
981 let address = OnionAddress::from_str(
982 "647qjf6w3evdbdpy7oidf5vda6rsjzsl5a6ofsaou2v77hj7dmn2spqd.onion:80",
983 )?;
984 assert_eq!(
985 TorServiceId::from_str("647qjf6w3evdbdpy7oidf5vda6rsjzsl5a6ofsaou2v77hj7dmn2spqd")?,
986 address.service_id
987 );
988 assert_eq!(80, address.service_port);
989
990 if let Ok(_) = OnionAddress::from_str("foobar:27") {
991 assert!(false);
992 }
993
994 if let Ok(_) = OnionAddress::from_str(
995 "647qjf6w3evdbdpy7oidf5vda6rsjzsl5a6ofsaou2v77hj7dmn2spqd.onion:abcd",
996 ) {
997 assert!(false);
998 }
999
1000 Ok(())
1001 }
1002}