fix error on setting dual-stack socket
This commit is contained in:
parent
9a61db3c94
commit
5dd3c920e4
@ -88,13 +88,20 @@ impl Endpoint {
|
|||||||
|
|
||||||
config.transport_config(Arc::new(tp_cfg));
|
config.transport_config(Arc::new(tp_cfg));
|
||||||
|
|
||||||
let socket = UdpSocket::bind(SocketAddr::from(([0, 0, 0, 0], 0)))?;
|
// Try to create an IPv4 socket as the placeholder first, if it fails, try IPv6.
|
||||||
|
let socket = UdpSocket::bind(SocketAddr::from((Ipv4Addr::UNSPECIFIED, 0)))
|
||||||
|
.or_else(|err| {
|
||||||
|
UdpSocket::bind(SocketAddr::from((Ipv6Addr::UNSPECIFIED, 0))).map_err(|_| err)
|
||||||
|
})
|
||||||
|
.map_err(|err| Error::Socket("failed to create endpoint UDP socket", err))?;
|
||||||
|
|
||||||
let mut ep = QuinnEndpoint::new(
|
let mut ep = QuinnEndpoint::new(
|
||||||
EndpointConfig::default(),
|
EndpointConfig::default(),
|
||||||
None,
|
None,
|
||||||
socket,
|
socket,
|
||||||
Arc::new(TokioRuntime),
|
Arc::new(TokioRuntime),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
ep.set_default_client_config(config);
|
ep.set_default_client_config(config);
|
||||||
|
|
||||||
let ep = Self {
|
let ep = Self {
|
||||||
@ -139,7 +146,12 @@ impl Endpoint {
|
|||||||
SocketAddr::from((Ipv6Addr::UNSPECIFIED, 0))
|
SocketAddr::from((Ipv6Addr::UNSPECIFIED, 0))
|
||||||
};
|
};
|
||||||
|
|
||||||
ep.rebind(UdpSocket::bind(bind_addr)?)?;
|
ep.rebind(
|
||||||
|
UdpSocket::bind(bind_addr).map_err(|err| {
|
||||||
|
Error::Socket("failed to create endpoint UDP socket", err)
|
||||||
|
})?,
|
||||||
|
)
|
||||||
|
.map_err(|err| Error::Socket("failed to rebind endpoint UDP socket", err))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let conn = ep.connect(addr, server_name)?;
|
let conn = ep.connect(addr, server_name)?;
|
||||||
|
@ -68,6 +68,8 @@ pub enum Error {
|
|||||||
LoadNativeCerts(IoError),
|
LoadNativeCerts(IoError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Rustls(#[from] RustlsError),
|
Rustls(#[from] RustlsError),
|
||||||
|
#[error("{0}: {1}")]
|
||||||
|
Socket(&'static str, IoError),
|
||||||
#[error("timeout establishing connection")]
|
#[error("timeout establishing connection")]
|
||||||
Timeout,
|
Timeout,
|
||||||
#[error("cannot resolve the server name")]
|
#[error("cannot resolve the server name")]
|
||||||
|
@ -3,7 +3,7 @@ use bytes::Bytes;
|
|||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use quinn::VarInt;
|
use quinn::VarInt;
|
||||||
use socket2::Socket;
|
use socket2::{Domain, Protocol, SockAddr, Socket, Type};
|
||||||
use socks5_proto::{Address, Reply};
|
use socks5_proto::{Address, Reply};
|
||||||
use socks5_server::{
|
use socks5_server::{
|
||||||
auth::{NoAuth, Password},
|
auth::{NoAuth, Password},
|
||||||
@ -30,7 +30,6 @@ static SERVER: OnceCell<Server> = OnceCell::new();
|
|||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
inner: Socks5Server,
|
inner: Socks5Server,
|
||||||
addr: SocketAddr,
|
|
||||||
dual_stack: Option<bool>,
|
dual_stack: Option<bool>,
|
||||||
max_pkt_size: usize,
|
max_pkt_size: usize,
|
||||||
next_assoc_id: AtomicU16,
|
next_assoc_id: AtomicU16,
|
||||||
@ -40,22 +39,38 @@ pub struct Server {
|
|||||||
impl Server {
|
impl Server {
|
||||||
pub async fn set_config(cfg: Local) -> Result<(), Error> {
|
pub async fn set_config(cfg: Local) -> Result<(), Error> {
|
||||||
let socket = {
|
let socket = {
|
||||||
let socket = Socket::from(TcpListener::bind(&cfg.server).await?.into_std()?);
|
let domain = match cfg.server {
|
||||||
|
SocketAddr::V4(_) => Domain::IPV4,
|
||||||
|
SocketAddr::V6(_) => Domain::IPV6,
|
||||||
|
};
|
||||||
|
|
||||||
|
let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))
|
||||||
|
.map_err(|err| Error::Socket("failed to create socks5 server socket", err))?;
|
||||||
|
|
||||||
if let Some(dual_stack) = cfg.dual_stack {
|
if let Some(dual_stack) = cfg.dual_stack {
|
||||||
if cfg.server.is_ipv4() && dual_stack {
|
socket.set_only_v6(!dual_stack).map_err(|err| {
|
||||||
return Err(Error::from(IoError::new(
|
Error::Socket("socks5 server dual-stack socket setting error", err)
|
||||||
ErrorKind::Unsupported,
|
})?;
|
||||||
"IPv4 socket cannot be dual stack",
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
socket.set_only_v6(!dual_stack)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.set_reuse_address(true)?;
|
socket.set_reuse_address(true).map_err(|err| {
|
||||||
|
Error::Socket("failed to set socks5 server socket to reuse_address", err)
|
||||||
|
})?;
|
||||||
|
|
||||||
TcpListener::from_std(StdTcpListener::from(socket))?
|
socket.set_nonblocking(true).map_err(|err| {
|
||||||
|
Error::Socket("failed setting socks5 server socket as non-blocking", err)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
socket
|
||||||
|
.bind(&SockAddr::from(cfg.server))
|
||||||
|
.map_err(|err| Error::Socket("failed to bind socks5 server socket", err))?;
|
||||||
|
|
||||||
|
socket
|
||||||
|
.listen(i32::MAX)
|
||||||
|
.map_err(|err| Error::Socket("failed to listen on socks5 server socket", err))?;
|
||||||
|
|
||||||
|
TcpListener::from_std(StdTcpListener::from(socket))
|
||||||
|
.map_err(|err| Error::Socket("failed to create socks5 server socket", err))?
|
||||||
};
|
};
|
||||||
|
|
||||||
let auth: Arc<dyn Auth + Send + Sync> = match (cfg.username, cfg.password) {
|
let auth: Arc<dyn Auth + Send + Sync> = match (cfg.username, cfg.password) {
|
||||||
@ -68,7 +83,6 @@ impl Server {
|
|||||||
|
|
||||||
let server = Self {
|
let server = Self {
|
||||||
inner: Socks5Server::new(socket, auth),
|
inner: Socks5Server::new(socket, auth),
|
||||||
addr: cfg.server,
|
|
||||||
dual_stack: cfg.dual_stack,
|
dual_stack: cfg.dual_stack,
|
||||||
max_pkt_size: cfg.max_packet_size,
|
max_pkt_size: cfg.max_packet_size,
|
||||||
next_assoc_id: AtomicU16::new(0),
|
next_assoc_id: AtomicU16::new(0),
|
||||||
@ -84,11 +98,10 @@ impl Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start() {
|
pub async fn start() {
|
||||||
let server = SERVER.get().unwrap();
|
log::warn!("[socks5] server started, listening on {}", Self::addr());
|
||||||
log::warn!("[socks5] server started, listening on {}", server.addr);
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match server.inner.accept().await {
|
match SERVER.get().unwrap().inner.accept().await {
|
||||||
Ok((conn, addr)) => {
|
Ok((conn, addr)) => {
|
||||||
log::debug!("[socks5] [{addr}] connection established");
|
log::debug!("[socks5] [{addr}] connection established");
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
@ -118,33 +131,55 @@ impl Server {
|
|||||||
assoc: Associate<associate::NeedReply>,
|
assoc: Associate<associate::NeedReply>,
|
||||||
_addr: Address,
|
_addr: Address,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
async fn get_assoc_socket() -> Result<Arc<AssociatedUdpSocket>, IoError> {
|
async fn get_assoc_socket() -> Result<Arc<AssociatedUdpSocket>, Error> {
|
||||||
let socket = Socket::from(
|
let domain = match Server::addr() {
|
||||||
UdpSocket::bind(SERVER.get().unwrap().addr)
|
SocketAddr::V4(_) => Domain::IPV4,
|
||||||
.await?
|
SocketAddr::V6(_) => Domain::IPV6,
|
||||||
.into_std()?,
|
};
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(dual_stack) = SERVER.get().unwrap().dual_stack {
|
let socket = Socket::new(domain, Type::DGRAM, Some(Protocol::UDP)).map_err(|err| {
|
||||||
// We already checked that the server address is IPv6
|
Error::Socket("failed to create socks5 server UDP associate socket", err)
|
||||||
socket.set_only_v6(!dual_stack)?;
|
})?;
|
||||||
|
|
||||||
|
if let Some(dual_stack) = Server::dual_stack() {
|
||||||
|
socket.set_only_v6(!dual_stack).map_err(|err| {
|
||||||
|
Error::Socket(
|
||||||
|
"socks5 server UDP associate dual-stack socket setting error",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let socket = AssociatedUdpSocket::from((
|
socket.set_nonblocking(true).map_err(|err| {
|
||||||
UdpSocket::from_std(StdUdpSocket::from(socket))?,
|
Error::Socket(
|
||||||
SERVER.get().unwrap().max_pkt_size,
|
"failed setting socks5 server UDP associate socket as non-blocking",
|
||||||
));
|
err,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(Arc::new(socket))
|
socket
|
||||||
|
.bind(&SockAddr::from(Server::addr()))
|
||||||
|
.map_err(|err| {
|
||||||
|
Error::Socket("failed to bind socks5 server UDP associate socket", err)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let socket = UdpSocket::from_std(StdUdpSocket::from(socket)).map_err(|err| {
|
||||||
|
Error::Socket("failed to create socks5 server UDP associate socket", err)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(Arc::new(AssociatedUdpSocket::from((
|
||||||
|
socket,
|
||||||
|
Server::max_pkt_size(),
|
||||||
|
))))
|
||||||
}
|
}
|
||||||
|
|
||||||
match get_assoc_socket()
|
match get_assoc_socket().await {
|
||||||
.await
|
Ok(assoc_socket) => {
|
||||||
.and_then(|socket| socket.local_addr().map(|addr| (socket, addr)))
|
|
||||||
{
|
|
||||||
Ok((assoc_socket, assoc_addr)) => {
|
|
||||||
let assoc = assoc
|
let assoc = assoc
|
||||||
.reply(Reply::Succeeded, Address::SocketAddress(assoc_addr))
|
.reply(
|
||||||
|
Reply::Succeeded,
|
||||||
|
Address::SocketAddress(assoc_socket.local_addr().unwrap()),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
Self::send_pkt(assoc, assoc_socket).await
|
Self::send_pkt(assoc, assoc_socket).await
|
||||||
}
|
}
|
||||||
@ -308,4 +343,16 @@ impl Server {
|
|||||||
Err(err) => log::error!("[socks5] [send] {err}"),
|
Err(err) => log::error!("[socks5] [send] {err}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn addr() -> SocketAddr {
|
||||||
|
SERVER.get().unwrap().inner.local_addr().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dual_stack() -> Option<bool> {
|
||||||
|
SERVER.get().unwrap().dual_stack
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_pkt_size() -> usize {
|
||||||
|
SERVER.get().unwrap().max_pkt_size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,8 +64,8 @@ pub enum Error {
|
|||||||
AuthFailed(Uuid),
|
AuthFailed(Uuid),
|
||||||
#[error("received packet from unexpected source")]
|
#[error("received packet from unexpected source")]
|
||||||
UnexpectedPacketSource,
|
UnexpectedPacketSource,
|
||||||
#[error("create UDP session socket failed: {0}")]
|
#[error("{0}: {1}")]
|
||||||
CreateUdpSessionSocket(IoError),
|
Socket(&'static str, IoError),
|
||||||
#[error("{0} resolved to {1} but IPv6 UDP relay disabled")]
|
#[error("{0} resolved to {1} but IPv6 UDP relaying is disabled")]
|
||||||
UdpRelayIpv6Disabled(Address, SocketAddr),
|
UdpRelayIpv6Disabled(Address, SocketAddr),
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ use quinn::{
|
|||||||
};
|
};
|
||||||
use register_count::{Counter, Register};
|
use register_count::{Counter, Register};
|
||||||
use rustls::{version, ServerConfig as RustlsServerConfig};
|
use rustls::{version, ServerConfig as RustlsServerConfig};
|
||||||
use socket2::Socket;
|
use socket2::{Domain, Protocol, SockAddr, Socket, Type};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{hash_map::Entry, HashMap},
|
collections::{hash_map::Entry, HashMap},
|
||||||
future::Future,
|
future::Future,
|
||||||
@ -95,23 +95,32 @@ impl Server {
|
|||||||
|
|
||||||
config.transport_config(Arc::new(tp_cfg));
|
config.transport_config(Arc::new(tp_cfg));
|
||||||
|
|
||||||
let socket = Socket::from(StdUdpSocket::bind(cfg.server)?);
|
let socket = {
|
||||||
|
let domain = match cfg.server {
|
||||||
|
SocketAddr::V4(_) => Domain::IPV4,
|
||||||
|
SocketAddr::V6(_) => Domain::IPV6,
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(dual_stack) = cfg.dual_stack {
|
let socket = Socket::new(domain, Type::DGRAM, Some(Protocol::UDP))
|
||||||
if cfg.server.is_ipv4() && dual_stack {
|
.map_err(|err| Error::Socket("failed to create endpoint UDP socket", err))?;
|
||||||
return Err(Error::from(IoError::new(
|
|
||||||
ErrorKind::Unsupported,
|
if let Some(dual_stack) = cfg.dual_stack {
|
||||||
"IPv4 socket cannot be dual stack",
|
socket.set_only_v6(!dual_stack).map_err(|err| {
|
||||||
)));
|
Error::Socket("endpoint dual-stack socket setting error", err)
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.set_only_v6(!dual_stack)?;
|
socket
|
||||||
}
|
.bind(&SockAddr::from(cfg.server))
|
||||||
|
.map_err(|err| Error::Socket("failed to bind endpoint UDP socket", err))?;
|
||||||
|
|
||||||
|
StdUdpSocket::from(socket)
|
||||||
|
};
|
||||||
|
|
||||||
let ep = Endpoint::new(
|
let ep = Endpoint::new(
|
||||||
EndpointConfig::default(),
|
EndpointConfig::default(),
|
||||||
Some(config),
|
Some(config),
|
||||||
StdUdpSocket::from(socket),
|
socket,
|
||||||
Arc::new(TokioRuntime),
|
Arc::new(TokioRuntime),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -492,11 +501,8 @@ impl Connection {
|
|||||||
(session.socket_v4.clone(), session.socket_v6.clone())
|
(session.socket_v4.clone(), session.socket_v6.clone())
|
||||||
}
|
}
|
||||||
Entry::Vacant(entry) => {
|
Entry::Vacant(entry) => {
|
||||||
let session = entry.insert(
|
let session = entry
|
||||||
UdpSession::new(assoc_id, self.clone(), self.udp_relay_ipv6)
|
.insert(UdpSession::new(assoc_id, self.clone(), self.udp_relay_ipv6).await?);
|
||||||
.await
|
|
||||||
.map_err(Error::CreateUdpSessionSocket)?,
|
|
||||||
);
|
|
||||||
|
|
||||||
(session.socket_v4.clone(), session.socket_v6.clone())
|
(session.socket_v4.clone(), session.socket_v6.clone())
|
||||||
}
|
}
|
||||||
@ -592,17 +598,33 @@ struct UdpSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UdpSession {
|
impl UdpSession {
|
||||||
async fn new(assoc_id: u16, conn: Connection, udp_relay_ipv6: bool) -> Result<Self, IoError> {
|
async fn new(assoc_id: u16, conn: Connection, udp_relay_ipv6: bool) -> Result<Self, Error> {
|
||||||
let socket_v4 =
|
let socket_v4 = Arc::new(
|
||||||
Arc::new(UdpSocket::bind(SocketAddr::from((Ipv4Addr::UNSPECIFIED, 0))).await?);
|
UdpSocket::bind(SocketAddr::from((Ipv4Addr::UNSPECIFIED, 0)))
|
||||||
|
.await
|
||||||
|
.map_err(|err| Error::Socket("failed to create UDP associate IPv4 socket", err))?,
|
||||||
|
);
|
||||||
let socket_v6 = if udp_relay_ipv6 {
|
let socket_v6 = if udp_relay_ipv6 {
|
||||||
let socket = Socket::from(
|
let socket = Socket::new(Domain::IPV6, Type::DGRAM, Some(Protocol::UDP))
|
||||||
UdpSocket::bind(SocketAddr::from((Ipv6Addr::UNSPECIFIED, 0)))
|
.map_err(|err| Error::Socket("failed to create UDP associate IPv6 socket", err))?;
|
||||||
.await?
|
|
||||||
.into_std()?,
|
|
||||||
);
|
|
||||||
|
|
||||||
socket.set_only_v6(true)?;
|
socket.set_nonblocking(true).map_err(|err| {
|
||||||
|
Error::Socket(
|
||||||
|
"failed setting UDP associate IPv6 socket as non-blocking",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
socket.set_only_v6(true).map_err(|err| {
|
||||||
|
Error::Socket("failed setting UDP associate IPv6 socket as IPv6-only", err)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
socket
|
||||||
|
.bind(&SockAddr::from(SocketAddr::from((
|
||||||
|
Ipv6Addr::UNSPECIFIED,
|
||||||
|
0,
|
||||||
|
))))
|
||||||
|
.map_err(|err| Error::Socket("failed to bind UDP associate IPv6 socket", err))?;
|
||||||
|
|
||||||
Some(Arc::new(UdpSocket::from_std(StdUdpSocket::from(socket))?))
|
Some(Arc::new(UdpSocket::from_std(StdUdpSocket::from(socket))?))
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user