Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c57300520 | ||
|
|
7757552bdc | ||
|
|
190727f325 | ||
|
|
4d7908229b | ||
|
|
988b280a85 | ||
|
|
86aee13347 | ||
|
|
cc2e2c2776 | ||
|
|
db75971b77 | ||
|
|
ae3e64c365 | ||
|
|
3bbb5f7955 | ||
|
|
15cc8f9d2d | ||
|
|
2e7055bdd1 | ||
|
|
d834f500fa |
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
@@ -218,13 +218,8 @@ jobs:
|
||||
matrix:
|
||||
target:
|
||||
- x86_64-apple-darwin
|
||||
- mips-unknown-linux-musl
|
||||
# - mipsel-unknown-linux-musl
|
||||
- x86_64-unknown-linux-musl
|
||||
# - i686-unknown-linux-musl
|
||||
- aarch64-unknown-linux-musl
|
||||
# - arm-unknown-linux-musleabi
|
||||
# - armv7-unknown-linux-musleabihf
|
||||
- x86_64-pc-windows-gnu
|
||||
steps:
|
||||
- name: download upload url
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"leaf",
|
||||
"leaf-bin",
|
||||
"leaf-cli",
|
||||
"leaf-ffi",
|
||||
"leaf-plugins/shadowsocks",
|
||||
]
|
||||
default-members = ["leaf-bin"]
|
||||
default-members = ["leaf-cli"]
|
||||
resolver = "2"
|
||||
|
||||
[profile.release]
|
||||
|
||||
8
Makefile
8
Makefile
@@ -5,11 +5,11 @@ export CFG_COMMIT_HASH := $(CFG_COMMIT_HASH)
|
||||
CFG_COMMIT_DATE := $(shell git log --format="%ci" -n 1)
|
||||
export CFG_COMMIT_DATE := $(CFG_COMMIT_DATE)
|
||||
|
||||
local:
|
||||
cargo build -p leaf-bin --release
|
||||
cli:
|
||||
cargo build -p leaf-cli --release
|
||||
|
||||
local-dev:
|
||||
cargo build -p leaf-bin
|
||||
cli-dev:
|
||||
cargo build -p leaf-cli
|
||||
|
||||
test:
|
||||
cargo test -p leaf -- --nocapture
|
||||
|
||||
@@ -334,7 +334,7 @@ level 可以是 trace, debug, info, warn, error
|
||||
"hosts": {
|
||||
"example.com": [
|
||||
"192.168.0.1",
|
||||
"192.168.0.2
|
||||
"192.168.0.2"
|
||||
],
|
||||
"server.com": [
|
||||
"192.168.0.3"
|
||||
@@ -1059,7 +1059,7 @@ V2Ray 的 `dat` 文件格式,可以有如下形式:
|
||||
|
||||
此外所有非组合类型的 outbound 必须正确配置一个 `bind` 地址,这是连接原网关的网卡的地址,即未连接 VPN 前网卡的 IP 地址:
|
||||
```json
|
||||
"outbounds: [
|
||||
"outbounds": [
|
||||
{
|
||||
"bind": "192.168.0.99",
|
||||
"protocol": "shadowsocks",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "leaf-bin"
|
||||
version = "0.10.8"
|
||||
name = "leaf-cli"
|
||||
version = "0.10.11"
|
||||
authors = ["eycorsican <eric.y.corsican@gmail.com>"]
|
||||
edition = "2021"
|
||||
|
||||
@@ -125,7 +125,7 @@ ctrlc = ["tokio/signal"]
|
||||
[dependencies]
|
||||
# Common
|
||||
tokio = { version = "1", features = ["sync", "io-util", "net", "time", "rt", "rt-multi-thread"] }
|
||||
protobuf = "3.3.0"
|
||||
protobuf = "=3.3.0"
|
||||
thiserror = "1.0"
|
||||
futures = "0.3"
|
||||
async-trait = "0.1"
|
||||
@@ -257,4 +257,4 @@ tokio = { version = "1", features = ["fs", "sync", "io-util", "net", "time", "rt
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
bindgen = "0.68"
|
||||
protobuf-codegen = "3.3.0"
|
||||
protobuf-codegen = "=3.3.0"
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::time::Duration;
|
||||
use async_recursion::async_recursion;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::{debug, info, trace, warn};
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use crate::{
|
||||
app::SyncDnsClient,
|
||||
@@ -132,7 +132,7 @@ impl Dispatcher {
|
||||
tag.to_owned()
|
||||
}
|
||||
Err(err) => {
|
||||
trace!("pick route failed: {}", err);
|
||||
debug!("pick route failed: {}", err);
|
||||
if let Some(tag) = self.outbound_manager.read().await.default_handler() {
|
||||
debug!(
|
||||
"picked default route [{}] for {} -> {}",
|
||||
@@ -267,7 +267,7 @@ impl Dispatcher {
|
||||
tag.to_owned()
|
||||
}
|
||||
Err(err) => {
|
||||
trace!("pick route failed: {}", err);
|
||||
debug!("pick route failed: {}", err);
|
||||
if let Some(tag) = self.outbound_manager.read().await.default_handler() {
|
||||
debug!(
|
||||
"picked default route [{}] for {} -> {}",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::collections::HashMap;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
use std::num::NonZeroUsize;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Weak};
|
||||
@@ -177,12 +177,21 @@ impl DnsClient {
|
||||
server: &SocketAddr,
|
||||
) -> Result<CacheEntry> {
|
||||
let socket = if is_direct {
|
||||
debug!("direct lookup");
|
||||
let socket = self.new_udp_socket(server).await?;
|
||||
Box::new(StdOutboundDatagram::new(socket))
|
||||
} else {
|
||||
debug!("dispatched lookup");
|
||||
if let Some(dispatcher_weak) = self.dispatcher.as_ref() {
|
||||
// The source address will be used to determine which address the
|
||||
// underlying socket will bind.
|
||||
let source = match server {
|
||||
SocketAddr::V4(_) => SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0),
|
||||
SocketAddr::V6(_) => SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0),
|
||||
};
|
||||
let sess = Session {
|
||||
network: Network::Udp,
|
||||
source,
|
||||
destination: SocksAddr::from(server),
|
||||
inbound_tag: "internal".to_string(),
|
||||
..Default::default()
|
||||
@@ -265,7 +274,7 @@ impl DnsClient {
|
||||
break;
|
||||
};
|
||||
let entry = CacheEntry { ips, deadline };
|
||||
trace!("ips for {}:\n{:#?}", host, &entry);
|
||||
debug!("ips for {}: {:#?}", host, &entry);
|
||||
return Ok(entry);
|
||||
} else {
|
||||
// response with 0 records
|
||||
|
||||
@@ -83,10 +83,9 @@ impl NatManager {
|
||||
let n_removed = n_total - n_remaining;
|
||||
drop(sessions); // release the lock
|
||||
if n_removed > 0 {
|
||||
trace!(
|
||||
debug!(
|
||||
"removed {} nat sessions, remaining {} sessions",
|
||||
n_removed,
|
||||
n_remaining
|
||||
n_removed, n_remaining
|
||||
);
|
||||
}
|
||||
tokio::time::sleep(Duration::from_secs(
|
||||
|
||||
@@ -7,7 +7,7 @@ use cidr::IpCidr;
|
||||
use futures::TryFutureExt;
|
||||
use maxminddb::geoip2::Country;
|
||||
use maxminddb::Mmap;
|
||||
use tracing::{debug, trace, warn};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use crate::app::SyncDnsClient;
|
||||
use crate::config;
|
||||
@@ -526,7 +526,7 @@ impl Router {
|
||||
if !ips.is_empty() {
|
||||
let mut new_sess = sess.clone();
|
||||
new_sess.destination = SocksAddr::from((ips[0], sess.destination.port()));
|
||||
trace!(
|
||||
debug!(
|
||||
"re-matching with resolved ip [{}] for [{}]",
|
||||
ips[0],
|
||||
sess.destination.host()
|
||||
|
||||
@@ -29,18 +29,18 @@ fn log_out(data: &[u8]) {
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
fn log_out(data: &[u8]) {
|
||||
if data.is_empty() {
|
||||
return;
|
||||
}
|
||||
unsafe {
|
||||
let s = match ffi::CString::new(data) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return,
|
||||
};
|
||||
const ANDROID_LOG_TAG: &str = "leaf";
|
||||
let tag = ffi::CString::new("leaf").unwrap();
|
||||
let _ = __android_log_print(
|
||||
android_LogPriority_ANDROID_LOG_VERBOSE as std::os::raw::c_int,
|
||||
ffi::CString::new(ANDROID_LOG_TAG)
|
||||
.unwrap()
|
||||
.as_c_str()
|
||||
.as_ptr(),
|
||||
tag.as_c_str().as_ptr(),
|
||||
s.as_c_str().as_ptr(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -68,28 +68,18 @@ impl OutboundDatagramSendHalf for StdOutboundDatagramSendHalf {
|
||||
}
|
||||
}
|
||||
|
||||
/// An outbound datagram simply wraps a UDP socket.
|
||||
pub struct SimpleOutboundDatagram {
|
||||
pub struct DomainResolveOutboundDatagram {
|
||||
inner: UdpSocket,
|
||||
destination: Option<SocksAddr>,
|
||||
dns_client: SyncDnsClient,
|
||||
}
|
||||
|
||||
impl SimpleOutboundDatagram {
|
||||
pub fn new(
|
||||
inner: UdpSocket,
|
||||
destination: Option<SocksAddr>,
|
||||
dns_client: SyncDnsClient,
|
||||
) -> Self {
|
||||
SimpleOutboundDatagram {
|
||||
inner,
|
||||
destination,
|
||||
dns_client,
|
||||
}
|
||||
impl DomainResolveOutboundDatagram {
|
||||
pub fn new(inner: UdpSocket, dns_client: SyncDnsClient) -> Self {
|
||||
Self { inner, dns_client }
|
||||
}
|
||||
}
|
||||
|
||||
impl OutboundDatagram for SimpleOutboundDatagram {
|
||||
impl OutboundDatagram for DomainResolveOutboundDatagram {
|
||||
fn split(
|
||||
self: Box<Self>,
|
||||
) -> (
|
||||
@@ -99,8 +89,100 @@ impl OutboundDatagram for SimpleOutboundDatagram {
|
||||
let r = Arc::new(self.inner);
|
||||
let s = r.clone();
|
||||
(
|
||||
Box::new(SimpleOutboundDatagramRecvHalf(r, self.destination)),
|
||||
Box::new(SimpleOutboundDatagramSendHalf(s, self.dns_client)),
|
||||
Box::new(DomainResolveOutboundDatagramRecvHalf(r)),
|
||||
Box::new(DomainResolveOutboundDatagramSendHalf(s, self.dns_client)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DomainResolveOutboundDatagramRecvHalf(Arc<UdpSocket>);
|
||||
|
||||
#[async_trait]
|
||||
impl OutboundDatagramRecvHalf for DomainResolveOutboundDatagramRecvHalf {
|
||||
async fn recv_from(&mut self, buf: &mut [u8]) -> io::Result<(usize, SocksAddr)> {
|
||||
match self.0.recv_from(buf).await {
|
||||
Ok((n, a)) => Ok((n, SocksAddr::Ip(unmapped_ipv4(a)))),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DomainResolveOutboundDatagramSendHalf(Arc<UdpSocket>, SyncDnsClient);
|
||||
|
||||
#[async_trait]
|
||||
impl OutboundDatagramSendHalf for DomainResolveOutboundDatagramSendHalf {
|
||||
async fn send_to(&mut self, buf: &[u8], target: &SocksAddr) -> io::Result<usize> {
|
||||
match target {
|
||||
SocksAddr::Domain(domain, port) => {
|
||||
let ips = self
|
||||
.1
|
||||
.read()
|
||||
.await
|
||||
.direct_lookup(domain)
|
||||
.map_err(|e| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("lookup {} failed: {}", domain, e),
|
||||
)
|
||||
})
|
||||
.await?;
|
||||
let ip = ips
|
||||
.first()
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "no results"))?;
|
||||
self.0.send_to(buf, SocketAddr::new(*ip, *port)).await
|
||||
}
|
||||
SocksAddr::Ip(addr) => self.0.send_to(buf, addr).await,
|
||||
}
|
||||
}
|
||||
|
||||
async fn close(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// An outbound datagram that sends to a domain target.
|
||||
pub struct DomainAssociatedOutboundDatagram {
|
||||
inner: UdpSocket,
|
||||
source: SocketAddr,
|
||||
destination: SocksAddr,
|
||||
dns_client: SyncDnsClient,
|
||||
}
|
||||
|
||||
impl DomainAssociatedOutboundDatagram {
|
||||
pub fn new(
|
||||
inner: UdpSocket,
|
||||
source: SocketAddr,
|
||||
destination: SocksAddr,
|
||||
dns_client: SyncDnsClient,
|
||||
) -> Self {
|
||||
DomainAssociatedOutboundDatagram {
|
||||
inner,
|
||||
source,
|
||||
destination,
|
||||
dns_client,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OutboundDatagram for DomainAssociatedOutboundDatagram {
|
||||
fn split(
|
||||
self: Box<Self>,
|
||||
) -> (
|
||||
Box<dyn OutboundDatagramRecvHalf>,
|
||||
Box<dyn OutboundDatagramSendHalf>,
|
||||
) {
|
||||
let r = Arc::new(self.inner);
|
||||
let s = r.clone();
|
||||
(
|
||||
Box::new(DomainAssociatedOutboundDatagramRecvHalf(
|
||||
r,
|
||||
self.destination,
|
||||
)),
|
||||
Box::new(DomainAssociatedOutboundDatagramSendHalf(
|
||||
s,
|
||||
self.source,
|
||||
self.dns_client,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -117,36 +199,30 @@ fn unmapped_ipv4(addr: SocketAddr) -> SocketAddr {
|
||||
addr
|
||||
}
|
||||
|
||||
pub struct SimpleOutboundDatagramRecvHalf(Arc<UdpSocket>, Option<SocksAddr>);
|
||||
pub struct DomainAssociatedOutboundDatagramRecvHalf(Arc<UdpSocket>, SocksAddr);
|
||||
|
||||
#[async_trait]
|
||||
impl OutboundDatagramRecvHalf for SimpleOutboundDatagramRecvHalf {
|
||||
impl OutboundDatagramRecvHalf for DomainAssociatedOutboundDatagramRecvHalf {
|
||||
async fn recv_from(&mut self, buf: &mut [u8]) -> io::Result<(usize, SocksAddr)> {
|
||||
match self.0.recv_from(buf).await {
|
||||
Ok((n, a)) => {
|
||||
if self.1.is_some() {
|
||||
Ok((n, self.1.as_ref().unwrap().clone()))
|
||||
} else {
|
||||
Ok((n, SocksAddr::Ip(unmapped_ipv4(a))))
|
||||
}
|
||||
}
|
||||
Ok((n, _a)) => Ok((n, self.1.clone())),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SimpleOutboundDatagramSendHalf(Arc<UdpSocket>, SyncDnsClient);
|
||||
pub struct DomainAssociatedOutboundDatagramSendHalf(Arc<UdpSocket>, SocketAddr, SyncDnsClient);
|
||||
|
||||
#[async_trait]
|
||||
impl OutboundDatagramSendHalf for SimpleOutboundDatagramSendHalf {
|
||||
impl OutboundDatagramSendHalf for DomainAssociatedOutboundDatagramSendHalf {
|
||||
async fn send_to(&mut self, buf: &[u8], target: &SocksAddr) -> io::Result<usize> {
|
||||
let addr = match target {
|
||||
SocksAddr::Domain(domain, port) => {
|
||||
let ips = {
|
||||
self.1
|
||||
self.2
|
||||
.read()
|
||||
.await
|
||||
.lookup(domain)
|
||||
.direct_lookup(domain)
|
||||
.map_err(|e| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
@@ -155,13 +231,20 @@ impl OutboundDatagramSendHalf for SimpleOutboundDatagramSendHalf {
|
||||
})
|
||||
.await?
|
||||
};
|
||||
if ips.is_empty() {
|
||||
// FIXME Since FakeDns returns IPv4 address only, it's always bound
|
||||
// to IPv4 address if FakeDns is used.
|
||||
//
|
||||
// If the socket was bound to an IPv4 address, we need an IPv4
|
||||
// address for sending, and vice versa for IPv6.
|
||||
let needs_ipv4 = self.1.is_ipv4();
|
||||
if let Some(ip) = ips.into_iter().find(|x| x.is_ipv4() == needs_ipv4) {
|
||||
SocketAddr::new(ip, port.to_owned())
|
||||
} else {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"could not resolve to any address",
|
||||
));
|
||||
}
|
||||
SocketAddr::new(ips[0], port.to_owned())
|
||||
}
|
||||
SocksAddr::Ip(a) => a.to_owned(),
|
||||
};
|
||||
|
||||
@@ -8,12 +8,12 @@ use async_trait::async_trait;
|
||||
use futures::future::select_ok;
|
||||
use futures::stream::Stream;
|
||||
use futures::TryFutureExt;
|
||||
use socket2::SockRef;
|
||||
use socket2::{Domain, SockRef, Socket, Type};
|
||||
use thiserror::Error;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tokio::net::{TcpSocket, TcpStream, UdpSocket};
|
||||
use tokio::time::timeout;
|
||||
use tracing::trace;
|
||||
use tracing::debug;
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::io::{AsFd, AsRawFd};
|
||||
@@ -83,11 +83,7 @@ pub mod vmess;
|
||||
#[cfg(any(feature = "inbound-ws", feature = "outbound-ws"))]
|
||||
pub mod ws;
|
||||
|
||||
pub use datagram::{
|
||||
SimpleInboundDatagram, SimpleInboundDatagramRecvHalf, SimpleInboundDatagramSendHalf,
|
||||
SimpleOutboundDatagram, SimpleOutboundDatagramRecvHalf, SimpleOutboundDatagramSendHalf,
|
||||
StdOutboundDatagram,
|
||||
};
|
||||
pub use datagram::*;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ProxyError {
|
||||
@@ -207,12 +203,12 @@ async fn bind_socket<T: BindSocket>(socket: &T, indicator: &SocketAddr) -> io::R
|
||||
match indicator.ip() {
|
||||
IpAddr::V4(v4) if v4.is_loopback() => {
|
||||
socket.bind(&SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 0).into())?;
|
||||
trace!("socket bind loopback v4");
|
||||
debug!("socket bind loopback v4");
|
||||
return Ok(());
|
||||
}
|
||||
IpAddr::V6(v6) if v6.is_loopback() => {
|
||||
socket.bind(&SocketAddrV6::new("::1".parse().unwrap(), 0, 0, 0).into())?;
|
||||
trace!("socket bind loopback v6");
|
||||
debug!("socket bind loopback v6");
|
||||
return Ok(());
|
||||
}
|
||||
_ => {}
|
||||
@@ -250,7 +246,7 @@ async fn bind_socket<T: BindSocket>(socket: &T, indicator: &SocketAddr) -> io::R
|
||||
last_err = Some(io::Error::last_os_error());
|
||||
continue;
|
||||
}
|
||||
trace!("socket bind {}", iface);
|
||||
debug!("socket bind {}", iface);
|
||||
return Ok(());
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
@@ -267,7 +263,7 @@ async fn bind_socket<T: BindSocket>(socket: &T, indicator: &SocketAddr) -> io::R
|
||||
last_err = Some(io::Error::last_os_error());
|
||||
continue;
|
||||
}
|
||||
trace!("socket bind {}", iface);
|
||||
debug!("socket bind {}", iface);
|
||||
return Ok(());
|
||||
}
|
||||
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
|
||||
@@ -286,7 +282,7 @@ async fn bind_socket<T: BindSocket>(socket: &T, indicator: &SocketAddr) -> io::R
|
||||
last_err = Some(e);
|
||||
continue;
|
||||
}
|
||||
trace!("socket bind {}", addr);
|
||||
debug!("socket bind {}", addr);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
@@ -302,26 +298,14 @@ async fn bind_socket<T: BindSocket>(socket: &T, indicator: &SocketAddr) -> io::R
|
||||
|
||||
// New UDP socket.
|
||||
pub async fn new_udp_socket(indicator: &SocketAddr) -> io::Result<UdpSocket> {
|
||||
use socket2::{Domain, Socket, Type};
|
||||
let socket = if *option::ENABLE_IPV6 {
|
||||
// Dual-stack socket.
|
||||
// FIXME Windows IPV6_V6ONLY?
|
||||
Socket::new(Domain::IPV6, Type::DGRAM, None)?
|
||||
} else {
|
||||
match indicator {
|
||||
SocketAddr::V4(..) => Socket::new(Domain::IPV4, Type::DGRAM, None)?,
|
||||
SocketAddr::V6(..) => Socket::new(Domain::IPV6, Type::DGRAM, None)?,
|
||||
}
|
||||
let socket = match indicator {
|
||||
SocketAddr::V4(..) => Socket::new(Domain::IPV4, Type::DGRAM, None)?,
|
||||
SocketAddr::V6(..) => Socket::new(Domain::IPV6, Type::DGRAM, None)?,
|
||||
};
|
||||
|
||||
socket.set_nonblocking(true)?;
|
||||
|
||||
// If the proxy request is coming from an inbound listens on the loopback,
|
||||
// the indicator could be a loopback address, we must ignore it.
|
||||
if indicator.ip().is_loopback() || *option::ENABLE_IPV6 {
|
||||
bind_socket(&socket, &*option::UNSPECIFIED_BIND_ADDR).await?;
|
||||
} else {
|
||||
bind_socket(&socket, indicator).await?;
|
||||
}
|
||||
bind_socket(&socket, indicator).await?;
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
protect_socket(socket.as_raw_fd()).await?;
|
||||
@@ -369,7 +353,7 @@ async fn tcp_dial_task(dial_addr: SocketAddr) -> io::Result<DialResult> {
|
||||
#[cfg(target_os = "android")]
|
||||
protect_socket(socket.as_raw_fd()).await?;
|
||||
|
||||
trace!("tcp dialing {}", &dial_addr);
|
||||
debug!("tcp dialing {}", &dial_addr);
|
||||
let start = tokio::time::Instant::now();
|
||||
let stream = timeout(
|
||||
Duration::from_secs(*option::OUTBOUND_DIAL_TIMEOUT),
|
||||
@@ -380,7 +364,7 @@ async fn tcp_dial_task(dial_addr: SocketAddr) -> io::Result<DialResult> {
|
||||
|
||||
apply_socket_opts(&stream)?;
|
||||
|
||||
trace!(
|
||||
debug!(
|
||||
"tcp {} <-> {} connected in {}ms",
|
||||
stream.local_addr()?,
|
||||
&dial_addr,
|
||||
@@ -423,7 +407,7 @@ pub async fn connect_datagram_outbound(
|
||||
Network::Udp => {
|
||||
let socket = new_udp_socket(&sess.source).await?;
|
||||
Ok(Some(OutboundTransport::Datagram(Box::new(
|
||||
SimpleOutboundDatagram::new(socket, None, dns_client.clone()),
|
||||
DomainResolveOutboundDatagram::new(socket, dns_client.clone()),
|
||||
))))
|
||||
}
|
||||
Network::Tcp => {
|
||||
@@ -431,18 +415,25 @@ pub async fn connect_datagram_outbound(
|
||||
Ok(Some(OutboundTransport::Stream(stream)))
|
||||
}
|
||||
},
|
||||
OutboundConnect::Direct => {
|
||||
let socket = new_udp_socket(&sess.source).await?;
|
||||
let dest = match &sess.destination {
|
||||
SocksAddr::Domain(domain, port) => {
|
||||
Some(SocksAddr::Domain(domain.to_owned(), port.to_owned()))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
Ok(Some(OutboundTransport::Datagram(Box::new(
|
||||
SimpleOutboundDatagram::new(socket, dest, dns_client.clone()),
|
||||
))))
|
||||
}
|
||||
OutboundConnect::Direct => match &sess.destination {
|
||||
SocksAddr::Domain(domain, port) => {
|
||||
let socket = new_udp_socket(&sess.source).await?;
|
||||
Ok(Some(OutboundTransport::Datagram(Box::new(
|
||||
DomainAssociatedOutboundDatagram::new(
|
||||
socket,
|
||||
sess.source.clone(),
|
||||
SocksAddr::Domain(domain.to_owned(), port.to_owned()),
|
||||
dns_client.clone(),
|
||||
),
|
||||
))))
|
||||
}
|
||||
SocksAddr::Ip(_) => {
|
||||
let socket = new_udp_socket(&sess.source).await?;
|
||||
Ok(Some(OutboundTransport::Datagram(Box::new(
|
||||
StdOutboundDatagram::new(socket),
|
||||
))))
|
||||
}
|
||||
},
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ cargo build -p $package $release_flag --no-default-features --features "default-
|
||||
cargo build -p $package $release_flag --no-default-features --features "default-openssl outbound-quic" --target x86_64-apple-ios
|
||||
cargo build -p $package $release_flag --no-default-features --features "default-ring outbound-quic" --target aarch64-apple-ios-sim
|
||||
|
||||
cargo install --force cbindgen
|
||||
|
||||
# Directories to put the libraries.
|
||||
rm -rf target/apple/$mode
|
||||
mkdir -p target/apple/$mode/include
|
||||
|
||||
Reference in New Issue
Block a user