|
|
|
@ -28,18 +28,19 @@ use dnscrypt_certs::*;
|
|
|
|
|
use errors::*;
|
|
|
|
|
use globals::*;
|
|
|
|
|
|
|
|
|
|
use byteorder::{BigEndian, ByteOrder};
|
|
|
|
|
use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
|
|
|
|
|
use clap::Arg;
|
|
|
|
|
use dnsstamps::{InformalProperty, WithInformalProperty};
|
|
|
|
|
use failure::{bail, ensure};
|
|
|
|
|
use futures::prelude::*;
|
|
|
|
|
use futures::{FutureExt, StreamExt};
|
|
|
|
|
use parking_lot::RwLock;
|
|
|
|
|
use rand::prelude::*;
|
|
|
|
|
use std::convert::TryFrom;
|
|
|
|
|
use std::mem;
|
|
|
|
|
use std::net::SocketAddr;
|
|
|
|
|
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
use std::time::Duration;
|
|
|
|
|
use tokio::net::{TcpListener, TcpStream, UdpSocket};
|
|
|
|
|
use tokio::prelude::*;
|
|
|
|
|
use tokio::runtime::{current_thread::Handle, Runtime};
|
|
|
|
@ -49,14 +50,12 @@ const DNSCRYPT_QUERY_MAX_SIZE: usize = 512;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
struct UdpClientCtx {
|
|
|
|
|
udp_socket_fd: RawFd,
|
|
|
|
|
packet: Vec<u8>,
|
|
|
|
|
net_udp_socket: std::net::UdpSocket,
|
|
|
|
|
client_addr: SocketAddr,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
struct TcpClientCtx {
|
|
|
|
|
packet: Vec<u8>,
|
|
|
|
|
client_connection: TcpStream,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -66,41 +65,65 @@ enum ClientCtx {
|
|
|
|
|
Tcp(TcpClientCtx),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn respond_to_query(client_ctx: ClientCtx) -> Result<(), Error> {
|
|
|
|
|
async fn respond_to_query(client_ctx: ClientCtx, packet: Vec<u8>) -> Result<(), Error> {
|
|
|
|
|
match client_ctx {
|
|
|
|
|
ClientCtx::Udp(client_ctx) => {
|
|
|
|
|
let packet = client_ctx.packet;
|
|
|
|
|
let udp_socket = unsafe { std::net::UdpSocket::from_raw_fd(client_ctx.udp_socket_fd) };
|
|
|
|
|
let _ = udp_socket.send_to(&packet, client_ctx.client_addr);
|
|
|
|
|
mem::forget(udp_socket);
|
|
|
|
|
let net_udp_socket = client_ctx.net_udp_socket;
|
|
|
|
|
net_udp_socket.send_to(&packet, client_ctx.client_addr)?;
|
|
|
|
|
}
|
|
|
|
|
ClientCtx::Tcp(client_ctx) => {
|
|
|
|
|
let packet_len = packet.len();
|
|
|
|
|
ensure!(packet_len <= DNS_MAX_PACKET_SIZE, "Packet too large");
|
|
|
|
|
let mut client_connection = client_ctx.client_connection;
|
|
|
|
|
let mut binlen = [0u8, 0];
|
|
|
|
|
BigEndian::write_u16(&mut binlen[..], packet_len as u16);
|
|
|
|
|
client_connection.write_all(&binlen).await?;
|
|
|
|
|
client_connection.write_all(&packet).await?;
|
|
|
|
|
}
|
|
|
|
|
ClientCtx::Tcp(client_ctx) => {}
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn handle_client_query(client_ctx: ClientCtx) -> Result<(), Error> {
|
|
|
|
|
// if let Some(synth_packet) =
|
|
|
|
|
// serve_certificates(&packet, &globals.provider_name, &globals.dnscrypt_certs)?
|
|
|
|
|
// {
|
|
|
|
|
// let _ = udp_socket.send_to(&synth_packet, client_addr).await;
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
// truncate(&mut packet);
|
|
|
|
|
// let _ = udp_socket.send_to(&packet, client_addr).await;
|
|
|
|
|
|
|
|
|
|
dbg!(&client_ctx);
|
|
|
|
|
respond_to_query(client_ctx).await
|
|
|
|
|
async fn handle_client_query(
|
|
|
|
|
globals: Arc<Globals>,
|
|
|
|
|
client_ctx: ClientCtx,
|
|
|
|
|
mut packet: Vec<u8>,
|
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
|
if let Some(synth_packet) =
|
|
|
|
|
serve_certificates(&packet, &globals.provider_name, &globals.dnscrypt_certs)?
|
|
|
|
|
{
|
|
|
|
|
return respond_to_query(client_ctx, synth_packet).await;
|
|
|
|
|
}
|
|
|
|
|
set_edns_max_payload_size(&mut packet, DNS_MAX_PACKET_SIZE as u16)?;
|
|
|
|
|
let original_tid = dns::tid(&packet);
|
|
|
|
|
let tid = random();
|
|
|
|
|
dns::set_tid(&mut packet, tid);
|
|
|
|
|
let mut ext_socket = UdpSocket::bind(&globals.external_addr).await?;
|
|
|
|
|
ext_socket.connect(&globals.upstream_addr).await?;
|
|
|
|
|
ext_socket.send(&packet).await.unwrap();
|
|
|
|
|
let mut response = vec![0u8; DNS_MAX_PACKET_SIZE];
|
|
|
|
|
let response_len = ext_socket.recv(&mut response[..]).await?;
|
|
|
|
|
ensure!(response_len > DNS_HEADER_SIZE, "Short packet");
|
|
|
|
|
response.truncate(response_len);
|
|
|
|
|
ensure!(dns::tid(&response) == tid, "Unexpected transaction ID");
|
|
|
|
|
ensure!(
|
|
|
|
|
dns::qname(&packet)? == dns::qname(&response)?,
|
|
|
|
|
"Unexpected query name in the response"
|
|
|
|
|
);
|
|
|
|
|
dns::set_tid(&mut response, original_tid);
|
|
|
|
|
respond_to_query(client_ctx, response).await
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn tcp_acceptor(globals: Arc<Globals>, tcp_listener: TcpListener) -> Result<(), Error> {
|
|
|
|
|
let runtime = globals.runtime.clone();
|
|
|
|
|
let mut tcp_listener = tcp_listener.incoming();
|
|
|
|
|
let timeout = globals.tcp_timeout;
|
|
|
|
|
while let Some(client) = tcp_listener.next().await {
|
|
|
|
|
let mut client_connection: TcpStream = match client {
|
|
|
|
|
Ok(client_connection) => client_connection,
|
|
|
|
|
Err(e) => bail!(e),
|
|
|
|
|
};
|
|
|
|
|
let globals = globals.clone();
|
|
|
|
|
runtime.spawn(
|
|
|
|
|
async {
|
|
|
|
|
let mut binlen = [0u8, 0];
|
|
|
|
@ -112,39 +135,46 @@ async fn tcp_acceptor(globals: Arc<Globals>, tcp_listener: TcpListener) -> Resul
|
|
|
|
|
);
|
|
|
|
|
let mut packet = vec![0u8; packet_len];
|
|
|
|
|
client_connection.read_exact(&mut packet).await?;
|
|
|
|
|
let client_ctx = ClientCtx::Tcp(TcpClientCtx {
|
|
|
|
|
packet,
|
|
|
|
|
client_connection,
|
|
|
|
|
});
|
|
|
|
|
let _ = handle_client_query(client_ctx).await;
|
|
|
|
|
let client_ctx = ClientCtx::Tcp(TcpClientCtx { client_connection });
|
|
|
|
|
let _ = handle_client_query(globals, client_ctx, packet).await;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
.timeout(timeout)
|
|
|
|
|
.map(|_| ()),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn udp_acceptor(globals: Arc<Globals>, mut udp_socket: UdpSocket) -> Result<(), Error> {
|
|
|
|
|
async fn udp_acceptor(
|
|
|
|
|
globals: Arc<Globals>,
|
|
|
|
|
net_udp_socket: std::net::UdpSocket,
|
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
|
let runtime = globals.runtime.clone();
|
|
|
|
|
let mut tokio_udp_socket = UdpSocket::try_from(net_udp_socket.try_clone()?)?;
|
|
|
|
|
let timeout = globals.udp_timeout;
|
|
|
|
|
loop {
|
|
|
|
|
let mut packet = vec![0u8; DNSCRYPT_QUERY_MAX_SIZE];
|
|
|
|
|
let (packet_len, client_addr) = udp_socket.recv_from(&mut packet).await?;
|
|
|
|
|
let udp_socket_fd = udp_socket.as_raw_fd();
|
|
|
|
|
let (packet_len, client_addr) = tokio_udp_socket.recv_from(&mut packet).await?;
|
|
|
|
|
let net_udp_socket = net_udp_socket.try_clone()?;
|
|
|
|
|
packet.truncate(packet_len);
|
|
|
|
|
let client_ctx = ClientCtx::Udp(UdpClientCtx {
|
|
|
|
|
udp_socket_fd,
|
|
|
|
|
packet,
|
|
|
|
|
net_udp_socket,
|
|
|
|
|
client_addr,
|
|
|
|
|
});
|
|
|
|
|
runtime.spawn(async { handle_client_query(client_ctx).await }.map(|_| ()));
|
|
|
|
|
let globals = globals.clone();
|
|
|
|
|
runtime.spawn(
|
|
|
|
|
async { handle_client_query(globals, client_ctx, packet).await }
|
|
|
|
|
.timeout(timeout)
|
|
|
|
|
.map(|_| ()),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn start(globals: Arc<Globals>, runtime: Arc<Runtime>) -> Result<(), Error> {
|
|
|
|
|
let socket_addr: SocketAddr = globals.listen_addr;
|
|
|
|
|
let tcp_listener = TcpListener::bind(&socket_addr).await?;
|
|
|
|
|
let udp_socket = UdpSocket::bind(&socket_addr).await?;
|
|
|
|
|
let udp_socket = std::net::UdpSocket::bind(&socket_addr)?;
|
|
|
|
|
runtime.spawn(tcp_acceptor(globals.clone(), tcp_listener).map(|_| {}));
|
|
|
|
|
runtime.spawn(udp_acceptor(globals.clone(), udp_socket).map(|_| {}));
|
|
|
|
|
Ok(())
|
|
|
|
@ -171,17 +201,46 @@ fn main() -> Result<(), Error> {
|
|
|
|
|
.required(true)
|
|
|
|
|
.help("Provider name"),
|
|
|
|
|
)
|
|
|
|
|
.arg(
|
|
|
|
|
Arg::with_name("upstream-addr")
|
|
|
|
|
.value_name("upstream-addr")
|
|
|
|
|
.takes_value(true)
|
|
|
|
|
.default_value("9.9.9.9:53")
|
|
|
|
|
.required(true)
|
|
|
|
|
.help("Address and port of the upstream server"),
|
|
|
|
|
)
|
|
|
|
|
.arg(
|
|
|
|
|
Arg::with_name("external-addr")
|
|
|
|
|
.value_name("external-addr")
|
|
|
|
|
.takes_value(true)
|
|
|
|
|
.default_value("0.0.0.0:0")
|
|
|
|
|
.required(true)
|
|
|
|
|
.help("Address and port to connect from"),
|
|
|
|
|
)
|
|
|
|
|
.get_matches();
|
|
|
|
|
|
|
|
|
|
let listen_addr = matches
|
|
|
|
|
.value_of("listen-addr")
|
|
|
|
|
.unwrap()
|
|
|
|
|
.to_ascii_lowercase();
|
|
|
|
|
|
|
|
|
|
let provider_name = match matches.value_of("provider-name").unwrap() {
|
|
|
|
|
provider_name if provider_name.starts_with("2.dnscrypt.") => provider_name.to_string(),
|
|
|
|
|
provider_name => format!("2.dnscrypt.{}", provider_name),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let listen_addr_s = matches.value_of("listen-addr").unwrap();
|
|
|
|
|
let listen_addr: SocketAddr = listen_addr_s.parse()?;
|
|
|
|
|
|
|
|
|
|
let upstream_addr_s = matches.value_of("upstream-addr").unwrap();
|
|
|
|
|
let upstream_addr: SocketAddr = upstream_addr_s.parse()?;
|
|
|
|
|
|
|
|
|
|
let external_addr_s = matches.value_of("external-addr").unwrap();
|
|
|
|
|
let external_addr: SocketAddr = external_addr_s.parse()?;
|
|
|
|
|
|
|
|
|
|
let udp_timeout = Duration::from_secs(10);
|
|
|
|
|
let tcp_timeout = Duration::from_secs(10);
|
|
|
|
|
|
|
|
|
|
let resolver_kp = SignKeyPair::new();
|
|
|
|
|
|
|
|
|
|
info!("Server address: {}", listen_addr);
|
|
|
|
@ -209,6 +268,10 @@ fn main() -> Result<(), Error> {
|
|
|
|
|
dnscrypt_certs: vec![dnscrypt_cert],
|
|
|
|
|
provider_name,
|
|
|
|
|
listen_addr,
|
|
|
|
|
upstream_addr,
|
|
|
|
|
external_addr,
|
|
|
|
|
tcp_timeout,
|
|
|
|
|
udp_timeout,
|
|
|
|
|
});
|
|
|
|
|
runtime.spawn(start(globals, runtime.clone()).map(|_| ()));
|
|
|
|
|
runtime.block_on(future::pending::<()>());
|
|
|
|
|