tor_client_lib/
control_connection.rs

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/// Generalization of the [std::net::SocketAddr] for Tor communication.
25/// Clients can communicate with the Tor server either through the standard TCP connection, or
26/// through a Unix socket.
27#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Deserialize, Serialize)]
28pub enum TorSocketAddr {
29    Tcp(TcpSocketAddr),
30    Unix(String),
31}
32
33impl TorSocketAddr {
34    /// Create the socket address from a TCP address string of the form "<ip>:<port>"
35    fn from_tcp_string(address: &str) -> Result<Self, AddrParseError> {
36        Ok(Self::Tcp(TcpSocketAddr::from_str(address)?))
37    }
38
39    /// Create the socket address from the path to the unix socket
40    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
52/// Convert from a [std::net::SocketAddr] to this
53impl 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/// Error returned when a given listen address type has a parse error
69#[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
110/// You can listen for data for an onion service either through TCP or a unix socket
111pub enum OnionServiceListener {
112    Tcp(TcpListener),
113    Unix(UnixListener),
114}
115
116impl OnionServiceListener {
117    /// Bind to the given socket address for listening
118    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    /// Accept an incoming connection from the listener
128    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
147/// A stream of data from an accepted listener socket
148pub 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/// Mapping from an Onion service virtual port to a local listen address
197#[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/// Onion address, containing a [TorServiceId] and a service port
226#[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/// Definition of a Tor Onion service (AKA "hidden service").
293///
294/// An onion service can be thought of as an encrypted load balancer, which presents itself as a
295/// virtual host in the Tor network, and which maps virtual ports on that virtual host to service
296/// ports running on your local machine. While, in practice, most onion services map a single
297/// virtual port to a service port, say, 443 to 443, you can map multiple virtual ports to a single
298/// service port, or a single virtual port to multiple service ports (in which case Tor will load
299/// balance the traffic coming in on the virtual port across the corresponding service ports).
300///
301/// Each onion service has the following:
302/// - The service ID contains all the information for the public key (see [TorServiceId] for
303/// details).
304/// - The signing, i.e, private, key for the onion service
305/// - The mapping from the virtual port(s) to the service port(s)
306#[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    /// Create a new `OnionService` object
315    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    /// Return all the listen addresses for a given onion address (including virtual port)
328    /// `onion_address` should be formatted as `<onion-address>:<port>`, e.g.
329    /// `joikeok6el5h5sbrojo2h3afw63lmfm7huvwtziacl34wjrx7n62gsad.onion:443`
330    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    /// Return all the listen addresses for the given local service port
340    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    /// Return the onion address (i.e., the onion hostname and virtual port) which maps to the
349    /// given local service port
350    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    /// Return a list of all the onion addresses for this onion service
365    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    /// Return the [TorServiceId] for this onion service
373    pub fn service_id(&self) -> &TorServiceId {
374        &self.service_id
375    }
376
377    /// Return the Tor signing key for this onion service
378    pub fn signing_key(&self) -> &TorEd25519SigningKey {
379        &self.signing_key
380    }
381
382    /// Return the list of virtual to service port mappings for this onion service
383    pub fn ports(&self) -> &Vec<OnionServiceMapping> {
384        &self.ports
385    }
386}
387
388/// Response returned by the Tor server in response to a command
389#[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
414/// Read a response to a controller command
415async fn read_control_response<S: StreamExt<Item = Result<String, LinesCodecError>> + Unpin>(
416    reader: &mut S,
417) -> Result<ControlResponse, TorError> {
418    lazy_static! {
419        // Mid reply
420        static ref MID_REGEX: Regex = Regex::new(r"^(?P<code>\d{3})-(?P<reply_line>.*)$").unwrap();
421
422        // Data reply
423        static ref DATA_REGEX: Regex =
424            Regex::new(r"^(?P<code>\d{3})\+(?P<reply_line>.*)$").unwrap();
425
426        // End of reply message
427        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            // Read Mid replies line-by-line, and append their reply lines to the reply
436            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                // For Data replies, append everything between the initial line and the "." to the reply line
444                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 the final "250 OK"
458                    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 we haven't gotten any other replies, use this one as the message
465                        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
482/// Read a response line
483async 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
493/// Format the ADD_ONION request arguments
494fn 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
525/// Parse a response field that is required, i.e., throw an error if it's not there
526fn 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    // Parse the Hash value
547    let hash_string =
548        parse_required_response_field(captures, "service_id", "ServiceID", "ADD_ONION")?;
549
550    // Retrieve the key, either the one passed in or the one
551    // returned from the controller
552    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    // Return the Onion Service
589    Ok(OnionService::new(service_id, returned_signing_key, ports))
590}
591
592/// ProtocolInfo struct, contains information from the response to the
593/// PROTOCOLINFO command
594#[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
601/// Control connection, used to send commands to and receive responses from
602/// the Tor server
603pub struct TorControlConnection {
604    reader: FramedRead<ReadHalf<TcpStream>, LinesCodec>,
605    writer: FramedWrite<WriteHalf<TcpStream>, LinesCodec>,
606    protocol_info: Option<ProtocolInfo>,
607}
608
609impl TorControlConnection {
610    /// Connect to the Tor server. This is generally how you create a connection to the server
611    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    /// Convert an existing TCPStream into a connection object
617    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    /// Write to the Tor Server
627    async fn write(&mut self, data: &str) -> Result<(), TorError> {
628        self.writer.send(data).await?;
629        Ok(())
630    }
631
632    /// Send the PROTOCOLINFO command and parse the response
633    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            // Parse the controller response
647            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    /// Send the GETINFO command and parse the response
685    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    /// Authenticate to the Tor server using the passed-in method
722    pub async fn authenticate(&mut self, method: TorAuthentication) -> Result<(), TorError> {
723        method.authenticate(self).await?;
724        Ok(())
725    }
726
727    /// Send a general command to the Tor server
728    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    /// Create an onion service.
749    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        // Create the request string from the arguments
756        let request_string = format_key_request_string(ports, transient, signing_key);
757
758        // Send command to Tor controller
759        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        // Parse the controller response
775        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        // Just in case someone passes in the ".onion" part
791        let service_id_string = service_id.replace(".onion", "");
792
793        // Send command to Tor controller
794        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        // 250 OK response
845        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        // garbled response
859        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        // Multiline response
869        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        // Data response
889        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}