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