1use std::any::Any;
3use std::boxed::Box;
4use std::convert::TryFrom;
5use std::io::{Read, Write};
6use std::net::{SocketAddr, TcpListener, TcpStream};
7use std::ops::{Deref, DerefMut};
8use std::str::FromStr;
9use std::sync::OnceLock;
10
11use domain::base::name::Name;
13use idna::uts46::{Hyphens, Uts46};
14use idna::{domain_to_ascii_cow, AsciiDenyList};
15use regex::Regex;
16
17use crate::tor_crypto::*;
19
20
21#[derive(thiserror::Error, Debug)]
23pub enum Error {
24 #[error("Failed to parse '{0}' as {1}")]
25 ParseFailure(String, String),
27
28 #[error("{0}")]
29 Generic(String),
31
32 #[error("Function not implemented")]
33 NotImplemented,
35}
36
37#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
45pub struct OnionAddrV3 {
46 pub(crate) service_id: V3OnionServiceId,
47 pub(crate) virt_port: u16,
48}
49
50impl OnionAddrV3 {
51 pub fn new(service_id: V3OnionServiceId, virt_port: u16) -> OnionAddrV3 {
53 OnionAddrV3 {
54 service_id,
55 virt_port,
56 }
57 }
58
59 pub fn service_id(&self) -> &V3OnionServiceId {
61 &self.service_id
62 }
63
64 pub fn virt_port(&self) -> u16 {
66 self.virt_port
67 }
68}
69
70impl std::fmt::Display for OnionAddrV3 {
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 write!(f, "{}.onion:{}", self.service_id, self.virt_port)
73 }
74}
75
76#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
78pub enum OnionAddr {
79 V3(OnionAddrV3),
80}
81
82impl FromStr for OnionAddr {
83 type Err = Error;
84 fn from_str(s: &str) -> Result<Self, Self::Err> {
85 static ONION_SERVICE_PATTERN: OnceLock<Regex> = OnceLock::new();
86 let onion_service_pattern = ONION_SERVICE_PATTERN.get_or_init(|| {
87 Regex::new(r"(?m)^(?P<service_id>[a-z2-7]{56})\.onion:(?P<port>[1-9][0-9]{0,4})$")
88 .unwrap()
89 });
90
91 if let Some(caps) = onion_service_pattern.captures(s.to_lowercase().as_ref()) {
92 let service_id = caps
93 .name("service_id")
94 .expect("missing service_id group")
95 .as_str()
96 .to_lowercase();
97 let port = caps.name("port").expect("missing port group").as_str();
98 if let (Ok(service_id), Ok(port)) = (
99 V3OnionServiceId::from_string(service_id.as_ref()),
100 u16::from_str(port),
101 ) {
102 return Ok(OnionAddr::V3(OnionAddrV3::new(service_id, port)));
103 }
104 }
105 Err(Self::Err::ParseFailure(s.to_string(), "OnionAddr".to_string()))
106 }
107}
108
109impl std::fmt::Display for OnionAddr {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 match self {
112 OnionAddr::V3(onion_addr) => onion_addr.fmt(f),
113 }
114 }
115}
116
117#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
125pub struct DomainAddr {
126 domain: String,
127 port: u16,
128}
129
130impl DomainAddr {
132 pub fn domain(&self) -> &str {
134 self.domain.as_ref()
135 }
136
137 pub fn port(&self) -> u16 {
139 self.port
140 }
141}
142
143impl std::fmt::Display for DomainAddr {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 let uts46: Uts46 = Default::default();
146 let (ui_str, _err) = uts46.to_user_interface(
147 self.domain.as_str().as_bytes(),
148 AsciiDenyList::URL,
149 Hyphens::Allow,
150 |_, _, _| -> bool { false },
151 );
152 write!(f, "{}:{}", ui_str, self.port)
153 }
154}
155
156impl TryFrom<(String, u16)> for DomainAddr {
157 type Error = Error;
158
159 fn try_from(value: (String, u16)) -> Result<Self, Self::Error> {
160 let (domain, port) = (&value.0, value.1);
161 if let Ok(domain) = domain_to_ascii_cow(domain.as_bytes(), AsciiDenyList::URL) {
162 let domain = domain.to_string();
163 if let Ok(domain) = Name::<Vec<u8>>::from_str(domain.as_ref()) {
164 let domain = domain.to_string();
165 if !domain.ends_with(".onion") {
166 return Ok(Self {
167 domain,
168 port,
169 });
170 }
171 }
172 }
173 Err(Self::Error::ParseFailure(format!(
174 "{}:{}",
175 domain, port
176 ), "DomainAddr".to_string()))
177 }
178}
179
180impl FromStr for DomainAddr {
181 type Err = Error;
182 fn from_str(s: &str) -> Result<Self, Self::Err> {
183 static DOMAIN_PATTERN: OnceLock<Regex> = OnceLock::new();
184 let domain_pattern = DOMAIN_PATTERN
185 .get_or_init(|| Regex::new(r"(?m)^(?P<domain>.*):(?P<port>[1-9][0-9]{0,4})$").unwrap());
186 if let Some(caps) = domain_pattern.captures(s) {
187 let domain = caps
188 .name("domain")
189 .expect("missing domain group")
190 .as_str()
191 .to_string();
192 let port = caps.name("port").expect("missing port group").as_str();
193 if let Ok(port) = u16::from_str(port) {
194 return Self::try_from((domain, port));
195 }
196 }
197 Err(Self::Err::ParseFailure(s.to_string(), "DomainAddr".to_string()))
198 }
199}
200
201#[derive(Clone, Debug, PartialEq, Eq)]
207pub enum TargetAddr {
208 Socket(std::net::SocketAddr),
210 OnionService(OnionAddr),
212 Domain(DomainAddr),
214}
215
216impl From<(V3OnionServiceId, u16)> for TargetAddr {
217 fn from(target_tuple: (V3OnionServiceId, u16)) -> Self {
218 TargetAddr::OnionService(OnionAddr::V3(OnionAddrV3::new(
219 target_tuple.0,
220 target_tuple.1,
221 )))
222 }
223}
224
225impl FromStr for TargetAddr {
226 type Err = Error;
227 fn from_str(s: &str) -> Result<Self, Self::Err> {
228 if let Ok(socket_addr) = SocketAddr::from_str(s) {
229 return Ok(TargetAddr::Socket(socket_addr));
230 } else if let Ok(onion_addr) = OnionAddr::from_str(s) {
231 return Ok(TargetAddr::OnionService(onion_addr));
232 } else if let Ok(domain_addr) = DomainAddr::from_str(s) {
233 return Ok(TargetAddr::Domain(domain_addr));
234 }
235 Err(Self::Err::ParseFailure(s.to_string(), "TargetAddr".to_string()))
236 }
237}
238
239impl std::fmt::Display for TargetAddr {
240 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
241 match self {
242 TargetAddr::Socket(socket_addr) => socket_addr.fmt(f),
243 TargetAddr::OnionService(onion_addr) => onion_addr.fmt(f),
244 TargetAddr::Domain(domain_addr) => domain_addr.fmt(f),
245 }
246 }
247}
248
249#[derive(Debug)]
251pub enum TorEvent {
252 BootstrapStatus {
254 progress: u32,
256 tag: String,
258 summary: String,
260 },
261 BootstrapComplete,
263 LogReceived {
265 line: String,
267 },
268 OnionServicePublished {
270 service_id: V3OnionServiceId,
272 },
273 ConnectComplete {
275 handle: ConnectHandle,
276 stream: OnionStream,
277 },
278 ConnectFailed {
280 handle: ConnectHandle,
281 error: Error,
282 },
283}
284
285pub type CircuitToken = usize;
287
288pub type ConnectHandle = usize;
290
291#[derive(Debug)]
299pub struct OnionStream {
300 pub(crate) stream: TcpStream,
301 pub(crate) local_addr: Option<OnionAddr>,
302 pub(crate) peer_addr: Option<TargetAddr>,
303}
304
305impl Deref for OnionStream {
306 type Target = TcpStream;
307 fn deref(&self) -> &Self::Target {
308 &self.stream
309 }
310}
311
312impl DerefMut for OnionStream {
313 fn deref_mut(&mut self) -> &mut Self::Target {
314 &mut self.stream
315 }
316}
317
318impl From<OnionStream> for TcpStream {
319 fn from(onion_stream: OnionStream) -> Self {
320 onion_stream.stream
321 }
322}
323
324impl Read for OnionStream {
325 fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
326 self.stream.read(buf)
327 }
328}
329
330impl Write for OnionStream {
331 fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
332 self.stream.write(buf)
333 }
334
335 fn flush(&mut self) -> Result<(), std::io::Error> {
336 self.stream.flush()
337 }
338}
339
340impl OnionStream {
341 pub fn peer_addr(&self) -> Option<TargetAddr> {
343 self.peer_addr.clone()
344 }
345
346 pub fn local_addr(&self) -> Option<OnionAddr> {
348 self.local_addr.clone()
349 }
350
351 pub fn try_clone(&self) -> Result<Self, std::io::Error> {
353 Ok(Self {
354 stream: self.stream.try_clone()?,
355 local_addr: self.local_addr.clone(),
356 peer_addr: self.peer_addr.clone(),
357 })
358 }
359}
360
361pub struct OnionListener {
369 pub(crate) listener: TcpListener,
370 pub(crate) onion_addr: OnionAddr,
371 pub(crate) data: Option<Box<dyn Any + Send>>,
372 pub(crate) drop: Option<Box<dyn FnMut(Box<dyn Any>) + Send>>,
373}
374
375impl OnionListener {
376 pub(crate) fn new<T: 'static + Send>(
378 listener: TcpListener,
379 onion_addr: OnionAddr,
380 data: T,
381 mut drop: impl FnMut(T) + 'static + Send) -> Self {
382 let data: Option<Box<dyn Any + Send>> = Some(Box::new(data));
384 let drop: Option<Box<dyn FnMut(Box<dyn Any>) + Send>> = Some(Box::new(move |data: Box<dyn std::any::Any>| {
386 if let Ok(data) = data.downcast::<T>() {
388 drop(*data);
390 }
391 }));
392
393 Self{
394 listener,
395 onion_addr,
396 data,
397 drop,
398 }
399 }
400
401 pub fn set_nonblocking(&self, nonblocking: bool) -> Result<(), std::io::Error> {
403 self.listener.set_nonblocking(nonblocking)
404 }
405
406 pub fn accept(&self) -> Result<Option<OnionStream>, std::io::Error> {
408 match self.listener.accept() {
409 Ok((stream, _socket_addr)) => Ok(Some(OnionStream {
410 stream,
411 local_addr: Some(self.onion_addr.clone()),
412 peer_addr: None,
413 })),
414 Err(err) => {
415 if err.kind() == std::io::ErrorKind::WouldBlock {
416 Ok(None)
417 } else {
418 Err(err)
419 }
420 }
421 }
422 }
423}
424
425impl Drop for OnionListener {
426 fn drop(&mut self) {
427 if let (Some(data), Some(mut drop)) = (self.data.take(), self.drop.take()) {
428 drop(data)
429 }
430 }
431}
432
433pub trait TorProvider: Send {
435 fn update(&mut self) -> Result<Vec<TorEvent>, Error>;
437 fn bootstrap(&mut self) -> Result<(), Error>;
439 fn add_client_auth(
441 &mut self,
442 service_id: &V3OnionServiceId,
443 client_auth: &X25519PrivateKey,
444 ) -> Result<(), Error>;
445 fn remove_client_auth(&mut self, service_id: &V3OnionServiceId) -> Result<(), Error>;
447 fn connect(
455 &mut self,
456 target: TargetAddr,
457 circuit: Option<CircuitToken>,
458 ) -> Result<OnionStream, Error>;
459 fn connect_async(
467 &mut self,
468 _target: TargetAddr,
469 _circuit: Option<CircuitToken>,
470 ) -> Result<ConnectHandle, Error> {
471 Err(Error::NotImplemented)
472 }
473 fn listener(
477 &mut self,
478 private_key: &Ed25519PrivateKey,
479 virt_port: u16,
480 authorised_clients: Option<&[X25519PublicKey]>,
481 ) -> Result<OnionListener, Error>;
482 fn generate_token(&mut self) -> CircuitToken;
484 fn release_token(&mut self, token: CircuitToken);
486}