summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2019-05-21 14:13:33 +0200
committerYorhel <git@yorhel.nl>2019-05-21 14:13:33 +0200
commitb44faa508cfa39939cebdefd107a0d10af3e682f (patch)
tree409131d7614cd3d6cd663e39dbd99eb5b6ab244a
parent914a762efb06f7c015eabf0ca3b2c2058f91f3c2 (diff)
Add method to create Onion servicesHEADmaster
-rw-r--r--src/err.rs2
-rw-r--r--src/sock.rs36
2 files changed, 37 insertions, 1 deletions
diff --git a/src/err.rs b/src/err.rs
index 8a5a2c5..33ae1b3 100644
--- a/src/err.rs
+++ b/src/err.rs
@@ -15,6 +15,7 @@ pub(crate) enum ErrorImpl {
Status(crate::sock::ReplyLine),
Parse, // This could be more specific
Keyword(String),
+ OnionKey,
}
impl std::fmt::Display for Error {
@@ -27,6 +28,7 @@ impl std::fmt::Display for Error {
Status(s) => write!(f, "Unexpected reply ({})", s),
Parse => write!(f, "Error parsing reply"),
Keyword(s) => write!(f, "Invalid keyword '{}'", s),
+ OnionKey => write!(f, "Invalid Onion private key"),
}
}
}
diff --git a/src/sock.rs b/src/sock.rs
index 15311db..bba3598 100644
--- a/src/sock.rs
+++ b/src/sock.rs
@@ -1,5 +1,5 @@
use std::io::{self,Read,Write};
-use std::net::{TcpStream,SocketAddr};
+use std::net::{TcpStream,TcpListener,SocketAddr};
use std::process::Child;
use std::sync::{Mutex,Condvar};
@@ -502,6 +502,40 @@ impl Tor {
self.socks
}
+ /// Open a Onion service at the specified (virtual) port. Returns its address (xyz.onion),
+ /// private key and listen socket. If no key is given, a new one is generated automatically.
+ /// The given key should be prefixed by its type (e.g.: `ED25519-V3:xxx`). the returned key
+ /// will have this prefix.
+ // TODO: Using a String for the key is ugly and easily confused with the public address, might
+ // want to use a separate type? (Or, perhaps even better, a return type encompassing all three
+ // values and having a Drop implementation that calls DEL_ONION).
+ pub fn listen_onion(&self, virtual_port: u16, key: Option<&str>) -> Result<(String, String, TcpListener)> {
+ let key = key.unwrap_or("NEW:ED25519-V3"); // tor 0.3.5.8 still defaults to v2 with "NEW:BEST" for some reason, just enforce v3 for now.
+ if key.contains(|c: char| c.is_whitespace()) { // Just to prevent protocol injection.
+ return Err(err!(OnionKey));
+ }
+ let listen = TcpListener::bind("127.0.0.1:0")?;
+ let local_port = listen.local_addr()?.port();
+ let r = self.cmd(format!("ADD_ONION {} Port={},127.0.0.1:{}\r\n", key, virtual_port, local_port))?;
+
+ let mut service = None;
+ let mut rkey = key.to_string();
+ for line in r {
+ if line.status != 250 {
+ return Err(err!(Parse));
+ }
+ if line.text.starts_with("ServiceID=") {
+ service = Some(format!("{}.onion", &line.text[10..]));
+ } else if line.text.starts_with("PrivateKey=") {
+ rkey = (&line.text[11..]).to_string();
+ }
+ }
+ match service {
+ None => return Err(err!(Parse)),
+ Some(s) => return Ok((s, rkey, listen))
+ }
+ }
+
/// Returns the most recent bootstrap status.
pub fn bootstrap_status(&self) -> Result<Box<BootstrapStatus>> {
let ret = self.getinfo(&["status/bootstrap-phase"])?;