mirror of
https://github.com/EasyTier/EasyTier.git
synced 2024-11-16 03:32:43 +08:00
parent
a0e59f5c56
commit
95a52a4b5c
|
@ -1,6 +1,6 @@
|
|||
use std::{
|
||||
collections::VecDeque,
|
||||
net::IpAddr,
|
||||
net::{IpAddr, SocketAddr},
|
||||
sync::Arc,
|
||||
task::{ready, Context, Poll},
|
||||
};
|
||||
|
@ -269,6 +269,39 @@ pub(crate) fn get_interface_name_by_ip(local_ip: &IpAddr) -> Option<String> {
|
|||
None
|
||||
}
|
||||
|
||||
pub(crate) fn setup_sokcet2(
|
||||
socket2_socket: &socket2::Socket,
|
||||
bind_addr: &SocketAddr,
|
||||
) -> Result<(), TunnelError> {
|
||||
socket2_socket.set_nonblocking(true)?;
|
||||
socket2_socket.set_reuse_address(true)?;
|
||||
socket2_socket.bind(&socket2::SockAddr::from(*bind_addr))?;
|
||||
|
||||
#[cfg(all(unix, not(target_os = "solaris"), not(target_os = "illumos")))]
|
||||
socket2_socket.set_reuse_port(true)?;
|
||||
|
||||
// linux/mac does not use interface of bind_addr to send packet, so we need to bind device
|
||||
// win can handle this with bind correctly
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
if let Some(dev_name) = super::common::get_interface_name_by_ip(&bind_addr.ip()) {
|
||||
// use IP_BOUND_IF to bind device
|
||||
unsafe {
|
||||
let dev_idx = nix::libc::if_nametoindex(dev_name.as_str().as_ptr() as *const i8);
|
||||
tracing::warn!(?dev_idx, ?dev_name, "bind device");
|
||||
socket2_socket.bind_device_by_index_v4(std::num::NonZeroU32::new(dev_idx))?;
|
||||
tracing::warn!(?dev_idx, ?dev_name, "bind device doen");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||
if let Some(dev_name) = super::common::get_interface_name_by_ip(&bind_addr.ip()) {
|
||||
tracing::trace!(dev_name = ?dev_name, "bind device");
|
||||
socket2_socket.bind_device(Some(dev_name.as_bytes()))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub mod tests {
|
||||
use std::time::Instant;
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ use futures::{stream::FuturesUnordered, StreamExt};
|
|||
use tokio::net::{TcpListener, TcpSocket, TcpStream};
|
||||
use tokio_util::codec::{FramedRead, FramedWrite, LengthDelimitedCodec};
|
||||
|
||||
use crate::tunnels::common::setup_sokcet2;
|
||||
|
||||
use super::{
|
||||
check_scheme_and_get_socket_addr, common::FramedTunnel, Tunnel, TunnelInfo, TunnelListener,
|
||||
};
|
||||
|
@ -112,32 +114,21 @@ impl TcpTunnelConnector {
|
|||
return get_tunnel_with_tcp_stream(stream, self.addr.clone().into());
|
||||
}
|
||||
|
||||
async fn connect_with_custom_bind(
|
||||
&mut self,
|
||||
is_ipv4: bool,
|
||||
) -> Result<Box<dyn Tunnel>, super::TunnelError> {
|
||||
async fn connect_with_custom_bind(&mut self) -> Result<Box<dyn Tunnel>, super::TunnelError> {
|
||||
let mut futures = FuturesUnordered::new();
|
||||
let dst_addr = check_scheme_and_get_socket_addr::<SocketAddr>(&self.addr, "tcp")?;
|
||||
|
||||
for bind_addr in self.bind_addrs.iter() {
|
||||
let socket = if is_ipv4 {
|
||||
TcpSocket::new_v4()?
|
||||
} else {
|
||||
TcpSocket::new_v6()?
|
||||
};
|
||||
socket.set_reuseaddr(true)?;
|
||||
tracing::info!(bind_addr = ?bind_addr, ?dst_addr, "bind addr");
|
||||
|
||||
#[cfg(all(unix, not(target_os = "solaris"), not(target_os = "illumos")))]
|
||||
socket.set_reuseport(true)?;
|
||||
let socket2_socket = socket2::Socket::new(
|
||||
socket2::Domain::for_address(dst_addr),
|
||||
socket2::Type::STREAM,
|
||||
Some(socket2::Protocol::TCP),
|
||||
)?;
|
||||
setup_sokcet2(&socket2_socket, bind_addr)?;
|
||||
|
||||
socket.bind(*bind_addr)?;
|
||||
// linux does not use interface of bind_addr to send packet, so we need to bind device
|
||||
// mac can handle this with bind correctly
|
||||
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
||||
if let Some(dev_name) = super::common::get_interface_name_by_ip(&bind_addr.ip()) {
|
||||
tracing::trace!(dev_name = ?dev_name, "bind device");
|
||||
socket.bind_device(Some(dev_name.as_bytes()))?;
|
||||
}
|
||||
let socket = TcpSocket::from_std_stream(socket2_socket.into());
|
||||
futures.push(socket.connect(dst_addr.clone()));
|
||||
}
|
||||
|
||||
|
@ -156,10 +147,8 @@ impl super::TunnelConnector for TcpTunnelConnector {
|
|||
async fn connect(&mut self) -> Result<Box<dyn Tunnel>, super::TunnelError> {
|
||||
if self.bind_addrs.is_empty() {
|
||||
self.connect_with_default_bind().await
|
||||
} else if self.bind_addrs[0].is_ipv4() {
|
||||
self.connect_with_custom_bind(true).await
|
||||
} else {
|
||||
self.connect_with_custom_bind(false).await
|
||||
self.connect_with_custom_bind().await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ use crate::{
|
|||
|
||||
use super::{
|
||||
codec::BytesCodec,
|
||||
common::{FramedTunnel, TunnelWithCustomInfo},
|
||||
common::{setup_sokcet2, FramedTunnel, TunnelWithCustomInfo},
|
||||
ring_tunnel::create_ring_tunnel_pair,
|
||||
DatagramSink, DatagramStream, Tunnel, TunnelListener,
|
||||
};
|
||||
|
@ -269,7 +269,14 @@ impl UdpTunnelListener {
|
|||
impl TunnelListener for UdpTunnelListener {
|
||||
async fn listen(&mut self) -> Result<(), super::TunnelError> {
|
||||
let addr = super::check_scheme_and_get_socket_addr::<SocketAddr>(&self.addr, "udp")?;
|
||||
self.socket = Some(Arc::new(UdpSocket::bind(addr).await?));
|
||||
|
||||
let socket2_socket = socket2::Socket::new(
|
||||
socket2::Domain::for_address(addr),
|
||||
socket2::Type::DGRAM,
|
||||
Some(socket2::Protocol::UDP),
|
||||
)?;
|
||||
setup_sokcet2(&socket2_socket, &addr)?;
|
||||
self.socket = Some(Arc::new(UdpSocket::from_std(socket2_socket.into())?));
|
||||
|
||||
let socket = self.socket.as_ref().unwrap().clone();
|
||||
let forward_tasks = self.forward_tasks.clone();
|
||||
|
|
Loading…
Reference in New Issue
Block a user