tor_rpc_connect/
client.rs1use std::{net::TcpStream, sync::Arc};
4
5#[cfg(unix)]
6use std::os::unix::net::UnixStream;
7
8use fs_mistrust::Mistrust;
9use tor_general_addr::general;
10
11use crate::{
12 ConnectError, ResolvedConnectPoint,
13 auth::{RpcAuth, RpcCookieSource, cookie::CookieLocation},
14 connpt::{AddrWithStr, AddressFile},
15};
16
17#[non_exhaustive]
19pub struct Connection {
20 pub stream: Stream,
24
25 pub auth: crate::auth::RpcAuth,
27}
28
29#[non_exhaustive]
31pub enum Stream {
32 Tcp(TcpStream),
34
35 #[cfg(unix)]
37 Unix(UnixStream),
38}
39
40impl ResolvedConnectPoint {
41 pub fn connect(&self, mistrust: &Mistrust) -> Result<Connection, ConnectError> {
46 use crate::connpt::ConnectPointEnum as CptE;
47 match &self.0 {
48 CptE::Connect(connect) => connect.do_connect(mistrust),
49 CptE::Builtin(builtin) => builtin.do_connect(),
50 }
51 }
52}
53impl crate::connpt::Builtin {
54 fn do_connect(&self) -> Result<Connection, ConnectError> {
56 use crate::connpt::BuiltinVariant as BV;
57 match self.builtin {
58 BV::Abort => Err(ConnectError::ExplicitAbort),
59 }
60 }
61}
62impl crate::connpt::Connect<crate::connpt::Resolved> {
63 fn find_connect_address(
66 &self,
67 mistrust: &Mistrust,
68 ) -> Result<AddrWithStr<general::SocketAddr>, ConnectError> {
69 use crate::connpt::ConnectAddress::*;
70
71 let mut addr = match &self.socket {
73 InetAuto(auto_addr) => {
74 let socket_address_file = self.socket_address_file.as_ref().ok_or_else(|| {
75 ConnectError::Internal(
76 "Absent socket_address_file should have been rejected earlier".into(),
77 )
78 })?;
79 let addr_from_disk = mistrust
80 .verifier()
81 .permit_readable()
82 .file_access()
83 .read_to_string(socket_address_file)
84 .map_err(ConnectError::SocketAddressFileAccess)?;
85 let addrfile: AddressFile = serde_json::from_str(&addr_from_disk)
86 .map_err(|e| ConnectError::SocketAddressFileJson(Arc::new(e)))?;
87 let address: AddrWithStr<general::SocketAddr> = addrfile
88 .address
89 .parse()
90 .map_err(ConnectError::SocketAddressFileContent)?;
91 auto_addr.validate_parsed_address(address.as_ref())?;
92 address
93 }
94 Socket(addr) => addr.clone(),
95 };
96 if let Some(canon) = &self.socket_canonical {
98 addr.set_string_from(canon);
99 }
100 Ok(addr)
101 }
102
103 fn do_connect(&self, mistrust: &Mistrust) -> Result<Connection, ConnectError> {
105 use crate::connpt::Auth;
106 use tor_general_addr::general::SocketAddr as SA;
107 let connect_to_address = self.find_connect_address(mistrust)?;
108 let auth = match &self.auth {
109 Auth::None => RpcAuth::Inherent,
110 Auth::Cookie { path } => RpcAuth::Cookie {
111 secret: RpcCookieSource::Unloaded(CookieLocation {
112 path: path.clone(),
113 mistrust: mistrust.clone(),
114 }),
115 server_address: connect_to_address.as_str().to_string(),
116 },
117 Auth::Unrecognized(_) => return Err(ConnectError::UnsupportedAuthType),
119 };
120 if let Some(sock_parent_dir) = crate::socket_parent_path(connect_to_address.as_ref()) {
121 mistrust.check_directory(sock_parent_dir)?;
122 }
123 let stream = match connect_to_address.as_ref() {
124 SA::Inet(addr) => {
125 let socket = TcpStream::connect(addr)?;
126 Stream::Tcp(socket)
127 }
128 #[cfg(unix)]
129 SA::Unix(addr) => {
130 let socket = UnixStream::connect_addr(addr)?;
131 Stream::Unix(socket)
132 }
133 _ => return Err(ConnectError::UnsupportedSocketType),
134 };
135
136 Ok(Connection { stream, auth })
137 }
138}