Loading Cargo.lock +12 −15 Original line number Diff line number Diff line Loading @@ -577,13 +577,15 @@ dependencies = [ ] [[package]] name = "dns-parser" version = "0.8.0" name = "dns-message-parser" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" checksum = "b393503f9263e08ba3efe0a3578cdde90d6da5ae1af232cc338640670451c992" dependencies = [ "byteorder", "quick-error", "base64", "bytes", "hex", "thiserror", ] [[package]] Loading Loading @@ -815,7 +817,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", "wasi 0.10.2+wasi-snapshot-preview1", "wasi 0.10.0+wasi-snapshot-preview1", "wasm-bindgen", ] Loading Loading @@ -1229,7 +1231,8 @@ version = "0.1.0" dependencies = [ "arti-client", "bytes", "dns-parser", "dns-message-parser", "futures", "log", "simple_logger", "smoltcp", Loading Loading @@ -1442,12 +1445,6 @@ dependencies = [ "unicode-xid", ] [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quickcheck" version = "1.0.3" Loading Loading @@ -2507,9 +2504,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasi" Loading crates/onion-tunnel/Cargo.toml +2 −1 Original line number Diff line number Diff line Loading @@ -5,7 +5,8 @@ edition = "2021" [dependencies] bytes = "~1.1.0" dns-parser = "0.8" dns-message-parser = "~0.6.0" futures = "0.3" log = "0.4" simple_logger = "1" smoltcp = { version = "0.8.0", default-features = false, features = ["log", "phy-tuntap_interface", "phy-raw_socket", "medium-ip", "socket-udp", "socket-tcp", "proto-ipv4", "proto-ipv6", "socket", "async"], git = "https://github.com/dgoulet-tor/smoltcp.git", rev = "8cb96670e672dfe6f7ef271ef1a3648734f94bfc" } Loading crates/onion-tunnel/src/dns.rs 0 → 100644 +74 −0 Original line number Diff line number Diff line use futures::stream::StreamExt; use log::{error, info}; use smoltcp::{ socket::{UdpPacketMetadata, UdpSocketBuffer}, wire::IpAddress, }; use crate::socket::UdpSocket; pub struct DnsManager { listener_udp_v4: UdpSocket, } impl DnsManager { pub fn new(iface: crate::socket::IFace) -> Self { let rx_buffer = UdpSocketBuffer::new(vec![UdpPacketMetadata::EMPTY], vec![0; 4096]); let tx_buffer = UdpSocketBuffer::new(vec![UdpPacketMetadata::EMPTY], vec![0; 4096]); let socket = smoltcp::socket::UdpSocket::new(rx_buffer, tx_buffer); let mut listener_udp_v4 = UdpSocket::new(iface, socket); listener_udp_v4.bind(IpAddress::v4(10, 42, 42, 53), 53); Self { listener_udp_v4 } } pub async fn start(&mut self) { info!("Starting DNS manager"); loop { tokio::select! { r = self.listener_udp_v4.next() => match r { Some((payload, endpoint)) => { let ret = dns_message_parser::Dns::decode(payload); match ret { Ok(p) => { let q = p.questions.get(0).unwrap(); info!("DNS Question: {} from {}", q, endpoint); let a = dns_message_parser::rr::A { domain_name: q.domain_name.clone(), ttl: 10, ipv4_addr: "10.42.42.254".parse().unwrap(), }; let rr = dns_message_parser::rr::RR::A(a); let flags = dns_message_parser::Flags { qr: true, opcode: dns_message_parser::Opcode::Query, aa: true, tc: false, rd: true, ra: false, ad: false, cd: false, rcode: dns_message_parser::RCode::NoError, }; let reply = dns_message_parser::Dns { id: p.id, flags, questions: Vec::new(), answers: vec![rr], authorities: Vec::new(), additionals: Vec::new(), }; let _ = self.listener_udp_v4.send(reply.encode().unwrap().as_ref(), endpoint); } Err(e) => error!("Unable to parse DNS request: {}", e), } } None => break, } } } } } crates/onion-tunnel/src/lib.rs +10 −0 Original line number Diff line number Diff line mod device; mod dns; mod parser; mod proxy; mod socket; use arti_client::{TorClient, TorClientConfig}; use device::VirtualDevice; use dns::DnsManager; use log::{debug, info}; use proxy::ArtiProxy; use smoltcp::{ Loading Loading @@ -72,9 +74,17 @@ impl OnionTunnel { tokio::spawn(async move { proxy.start().await }); } fn dns(&mut self) { let mut dns_manager = DnsManager::new(self.iface.clone()); tokio::spawn(async move { dns_manager.start().await }); } pub async fn start(&mut self) { info!("Starting onion tunnel on TUN iface {}", self.iface_name); // Spawn the DNS manager service. self.dns(); loop { let timestamp = smoltcp::time::Instant::now(); Loading crates/onion-tunnel/src/socket.rs +27 −78 Original line number Diff line number Diff line Loading @@ -5,15 +5,18 @@ use std::{ task::{Context, Poll}, }; use bytes::Bytes; use futures::Stream; use smoltcp::{ iface::{Interface, SocketHandle}, phy::TunTapInterface, wire::IpEndpoint, }; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use crate::device::VirtualDevice; type IFace = Arc<Mutex<Interface<'static, VirtualDevice<TunTapInterface>>>>; pub type IFace = Arc<Mutex<Interface<'static, VirtualDevice<TunTapInterface>>>>; pub struct TcpSocket { handle: SocketHandle, Loading @@ -39,12 +42,22 @@ impl UdpSocket { .get_socket::<smoltcp::socket::UdpSocket>(self.handle)) } pub fn dest(&mut self) -> (IpAddr, u16) { pub fn bind(&mut self, addr: smoltcp::wire::IpAddress, port: u16) { self.with(|s| { let endpoint = s.endpoint(); (endpoint.addr.into(), endpoint.port) s.bind((addr, port)).expect("Unable to UDP bind"); }) } pub fn send(&mut self, payload: &[u8], endpoint: IpEndpoint) { self.with(|s| { let _ = s.send_slice(payload, endpoint); }); let _ = self .iface .lock() .unwrap() .poll(smoltcp::time::Instant::now()); } } impl Drop for UdpSocket { Loading @@ -53,33 +66,17 @@ impl Drop for UdpSocket { } } impl AsyncRead for UdpSocket { fn poll_read( mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<std::io::Result<()>> { impl Stream for UdpSocket { type Item = (Bytes, IpEndpoint); fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { self.with(|s| match s.can_recv() { true => { let rbuf = s.recv(); match rbuf { Err(e) => { return Poll::Ready(Err(std::io::Error::new( std::io::ErrorKind::Other, format!("{}", e), ))) } Ok((payload, _)) => { if payload.len() > 0 { buf.put_slice(payload); Poll::Ready(Ok(())) } else { s.register_recv_waker(cx.waker()); Poll::Pending } } } true => match s.recv() { Err(_) => Poll::Ready(None), Ok((payload, endpoint)) => { Poll::Ready(Some((Bytes::copy_from_slice(payload), endpoint.clone()))) } }, false => { s.register_recv_waker(cx.waker()); Poll::Pending Loading @@ -88,53 +85,6 @@ impl AsyncRead for UdpSocket { } } impl AsyncWrite for UdpSocket { fn poll_write( mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll<std::io::Result<usize>> { let dest = self.dest().into(); let p = self.with(|s| match s.can_send() { true => match s.send_slice(buf, dest) { Ok(_) => { s.register_send_waker(cx.waker()); Poll::Pending } Err(e) => Poll::Ready(Err(std::io::Error::new( std::io::ErrorKind::Other, format!("{}", e), ))), }, false => { s.register_send_waker(cx.waker()); Poll::Pending } }); match p { Poll::Ready(_) => { // We need to poll in order to process the ingress packets. let _ = self .iface .lock() .unwrap() .poll(smoltcp::time::Instant::now()); } _ => (), }; p } fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<std::io::Result<()>> { Poll::Ready(Ok(())) } fn poll_shutdown(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<std::io::Result<()>> { self.with(|s| s.close()); Poll::Ready(Ok(())) } } impl TcpSocket { pub fn new(iface: IFace, s: smoltcp::socket::TcpSocket<'static>) -> Self { let handle = iface.lock().unwrap().add_socket(s); Loading Loading @@ -240,8 +190,7 @@ impl AsyncWrite for TcpSocket { } fn poll_shutdown(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<std::io::Result<()>> { // XXX: Maybe should be close() and then check the state? self.with(|s| s.abort()); self.with(|s| s.close()); Poll::Ready(Ok(())) } } Loading
Cargo.lock +12 −15 Original line number Diff line number Diff line Loading @@ -577,13 +577,15 @@ dependencies = [ ] [[package]] name = "dns-parser" version = "0.8.0" name = "dns-message-parser" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" checksum = "b393503f9263e08ba3efe0a3578cdde90d6da5ae1af232cc338640670451c992" dependencies = [ "byteorder", "quick-error", "base64", "bytes", "hex", "thiserror", ] [[package]] Loading Loading @@ -815,7 +817,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", "wasi 0.10.2+wasi-snapshot-preview1", "wasi 0.10.0+wasi-snapshot-preview1", "wasm-bindgen", ] Loading Loading @@ -1229,7 +1231,8 @@ version = "0.1.0" dependencies = [ "arti-client", "bytes", "dns-parser", "dns-message-parser", "futures", "log", "simple_logger", "smoltcp", Loading Loading @@ -1442,12 +1445,6 @@ dependencies = [ "unicode-xid", ] [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quickcheck" version = "1.0.3" Loading Loading @@ -2507,9 +2504,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasi" Loading
crates/onion-tunnel/Cargo.toml +2 −1 Original line number Diff line number Diff line Loading @@ -5,7 +5,8 @@ edition = "2021" [dependencies] bytes = "~1.1.0" dns-parser = "0.8" dns-message-parser = "~0.6.0" futures = "0.3" log = "0.4" simple_logger = "1" smoltcp = { version = "0.8.0", default-features = false, features = ["log", "phy-tuntap_interface", "phy-raw_socket", "medium-ip", "socket-udp", "socket-tcp", "proto-ipv4", "proto-ipv6", "socket", "async"], git = "https://github.com/dgoulet-tor/smoltcp.git", rev = "8cb96670e672dfe6f7ef271ef1a3648734f94bfc" } Loading
crates/onion-tunnel/src/dns.rs 0 → 100644 +74 −0 Original line number Diff line number Diff line use futures::stream::StreamExt; use log::{error, info}; use smoltcp::{ socket::{UdpPacketMetadata, UdpSocketBuffer}, wire::IpAddress, }; use crate::socket::UdpSocket; pub struct DnsManager { listener_udp_v4: UdpSocket, } impl DnsManager { pub fn new(iface: crate::socket::IFace) -> Self { let rx_buffer = UdpSocketBuffer::new(vec![UdpPacketMetadata::EMPTY], vec![0; 4096]); let tx_buffer = UdpSocketBuffer::new(vec![UdpPacketMetadata::EMPTY], vec![0; 4096]); let socket = smoltcp::socket::UdpSocket::new(rx_buffer, tx_buffer); let mut listener_udp_v4 = UdpSocket::new(iface, socket); listener_udp_v4.bind(IpAddress::v4(10, 42, 42, 53), 53); Self { listener_udp_v4 } } pub async fn start(&mut self) { info!("Starting DNS manager"); loop { tokio::select! { r = self.listener_udp_v4.next() => match r { Some((payload, endpoint)) => { let ret = dns_message_parser::Dns::decode(payload); match ret { Ok(p) => { let q = p.questions.get(0).unwrap(); info!("DNS Question: {} from {}", q, endpoint); let a = dns_message_parser::rr::A { domain_name: q.domain_name.clone(), ttl: 10, ipv4_addr: "10.42.42.254".parse().unwrap(), }; let rr = dns_message_parser::rr::RR::A(a); let flags = dns_message_parser::Flags { qr: true, opcode: dns_message_parser::Opcode::Query, aa: true, tc: false, rd: true, ra: false, ad: false, cd: false, rcode: dns_message_parser::RCode::NoError, }; let reply = dns_message_parser::Dns { id: p.id, flags, questions: Vec::new(), answers: vec![rr], authorities: Vec::new(), additionals: Vec::new(), }; let _ = self.listener_udp_v4.send(reply.encode().unwrap().as_ref(), endpoint); } Err(e) => error!("Unable to parse DNS request: {}", e), } } None => break, } } } } }
crates/onion-tunnel/src/lib.rs +10 −0 Original line number Diff line number Diff line mod device; mod dns; mod parser; mod proxy; mod socket; use arti_client::{TorClient, TorClientConfig}; use device::VirtualDevice; use dns::DnsManager; use log::{debug, info}; use proxy::ArtiProxy; use smoltcp::{ Loading Loading @@ -72,9 +74,17 @@ impl OnionTunnel { tokio::spawn(async move { proxy.start().await }); } fn dns(&mut self) { let mut dns_manager = DnsManager::new(self.iface.clone()); tokio::spawn(async move { dns_manager.start().await }); } pub async fn start(&mut self) { info!("Starting onion tunnel on TUN iface {}", self.iface_name); // Spawn the DNS manager service. self.dns(); loop { let timestamp = smoltcp::time::Instant::now(); Loading
crates/onion-tunnel/src/socket.rs +27 −78 Original line number Diff line number Diff line Loading @@ -5,15 +5,18 @@ use std::{ task::{Context, Poll}, }; use bytes::Bytes; use futures::Stream; use smoltcp::{ iface::{Interface, SocketHandle}, phy::TunTapInterface, wire::IpEndpoint, }; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use crate::device::VirtualDevice; type IFace = Arc<Mutex<Interface<'static, VirtualDevice<TunTapInterface>>>>; pub type IFace = Arc<Mutex<Interface<'static, VirtualDevice<TunTapInterface>>>>; pub struct TcpSocket { handle: SocketHandle, Loading @@ -39,12 +42,22 @@ impl UdpSocket { .get_socket::<smoltcp::socket::UdpSocket>(self.handle)) } pub fn dest(&mut self) -> (IpAddr, u16) { pub fn bind(&mut self, addr: smoltcp::wire::IpAddress, port: u16) { self.with(|s| { let endpoint = s.endpoint(); (endpoint.addr.into(), endpoint.port) s.bind((addr, port)).expect("Unable to UDP bind"); }) } pub fn send(&mut self, payload: &[u8], endpoint: IpEndpoint) { self.with(|s| { let _ = s.send_slice(payload, endpoint); }); let _ = self .iface .lock() .unwrap() .poll(smoltcp::time::Instant::now()); } } impl Drop for UdpSocket { Loading @@ -53,33 +66,17 @@ impl Drop for UdpSocket { } } impl AsyncRead for UdpSocket { fn poll_read( mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<std::io::Result<()>> { impl Stream for UdpSocket { type Item = (Bytes, IpEndpoint); fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { self.with(|s| match s.can_recv() { true => { let rbuf = s.recv(); match rbuf { Err(e) => { return Poll::Ready(Err(std::io::Error::new( std::io::ErrorKind::Other, format!("{}", e), ))) } Ok((payload, _)) => { if payload.len() > 0 { buf.put_slice(payload); Poll::Ready(Ok(())) } else { s.register_recv_waker(cx.waker()); Poll::Pending } } } true => match s.recv() { Err(_) => Poll::Ready(None), Ok((payload, endpoint)) => { Poll::Ready(Some((Bytes::copy_from_slice(payload), endpoint.clone()))) } }, false => { s.register_recv_waker(cx.waker()); Poll::Pending Loading @@ -88,53 +85,6 @@ impl AsyncRead for UdpSocket { } } impl AsyncWrite for UdpSocket { fn poll_write( mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll<std::io::Result<usize>> { let dest = self.dest().into(); let p = self.with(|s| match s.can_send() { true => match s.send_slice(buf, dest) { Ok(_) => { s.register_send_waker(cx.waker()); Poll::Pending } Err(e) => Poll::Ready(Err(std::io::Error::new( std::io::ErrorKind::Other, format!("{}", e), ))), }, false => { s.register_send_waker(cx.waker()); Poll::Pending } }); match p { Poll::Ready(_) => { // We need to poll in order to process the ingress packets. let _ = self .iface .lock() .unwrap() .poll(smoltcp::time::Instant::now()); } _ => (), }; p } fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<std::io::Result<()>> { Poll::Ready(Ok(())) } fn poll_shutdown(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<std::io::Result<()>> { self.with(|s| s.close()); Poll::Ready(Ok(())) } } impl TcpSocket { pub fn new(iface: IFace, s: smoltcp::socket::TcpSocket<'static>) -> Self { let handle = iface.lock().unwrap().add_socket(s); Loading Loading @@ -240,8 +190,7 @@ impl AsyncWrite for TcpSocket { } fn poll_shutdown(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<std::io::Result<()>> { // XXX: Maybe should be close() and then check the state? self.with(|s| s.abort()); self.with(|s| s.close()); Poll::Ready(Ok(())) } }