UDP Associate

This commit is contained in:
ssrlive 2023-08-10 12:57:35 +08:00
parent 382c2ac6e3
commit 94835c41a4
3 changed files with 30 additions and 10 deletions

View file

@ -391,7 +391,7 @@ impl ConnectionManager for HttpManager {
info.protocol == IpProtocol::Tcp info.protocol == IpProtocol::Tcp
} }
fn new_tcp_proxy(&self, info: &ConnectionInfo) -> Result<Box<dyn TcpProxy>, Error> { fn new_tcp_proxy(&self, info: &ConnectionInfo, _: bool) -> Result<Box<dyn TcpProxy>, Error> {
if info.protocol != IpProtocol::Tcp { if info.protocol != IpProtocol::Tcp {
return Err("Invalid protocol".into()); return Err("Invalid protocol".into());
} }

View file

@ -1,5 +1,5 @@
use crate::{ use crate::{
error::Error, error::{Error, Result},
tun2proxy::{ tun2proxy::{
ConnectionInfo, ConnectionManager, Direction, IncomingDataEvent, IncomingDirection, OutgoingDataEvent, ConnectionInfo, ConnectionManager, Direction, IncomingDataEvent, IncomingDirection, OutgoingDataEvent,
OutgoingDirection, TcpProxy, OutgoingDirection, TcpProxy,
@ -7,7 +7,7 @@ use crate::{
}; };
use smoltcp::wire::IpProtocol; use smoltcp::wire::IpProtocol;
use socks5_impl::protocol::{self, handshake, password_method, Address, AuthMethod, StreamOperation, UserKey, Version}; use socks5_impl::protocol::{self, handshake, password_method, Address, AuthMethod, StreamOperation, UserKey, Version};
use std::{collections::VecDeque, net::SocketAddr}; use std::{collections::VecDeque, convert::TryFrom, net::SocketAddr};
#[derive(Eq, PartialEq, Debug)] #[derive(Eq, PartialEq, Debug)]
#[allow(dead_code)] #[allow(dead_code)]
@ -31,10 +31,17 @@ struct SocksProxyImpl {
data_buf: VecDeque<u8>, data_buf: VecDeque<u8>,
version: Version, version: Version,
credentials: Option<UserKey>, credentials: Option<UserKey>,
command: protocol::Command,
udp_associate: Option<SocketAddr>,
} }
impl SocksProxyImpl { impl SocksProxyImpl {
fn new(info: &ConnectionInfo, credentials: Option<UserKey>, version: Version) -> Result<Self, Error> { fn new(
info: &ConnectionInfo,
credentials: Option<UserKey>,
version: Version,
command: protocol::Command,
) -> Result<Self> {
let mut result = Self { let mut result = Self {
info: info.clone(), info: info.clone(),
state: SocksState::ServerHello, state: SocksState::ServerHello,
@ -45,6 +52,8 @@ impl SocksProxyImpl {
data_buf: VecDeque::default(), data_buf: VecDeque::default(),
version, version,
credentials, credentials,
command,
udp_associate: None,
}; };
result.send_client_hello()?; result.send_client_hello()?;
Ok(result) Ok(result)
@ -195,8 +204,7 @@ impl SocksProxyImpl {
} }
fn send_request_socks5(&mut self) -> Result<(), Error> { fn send_request_socks5(&mut self) -> Result<(), Error> {
protocol::Request::new(protocol::Command::Connect, self.info.dst.clone()) protocol::Request::new(self.command, self.info.dst.clone()).write_to_stream(&mut self.server_outbuf)?;
.write_to_stream(&mut self.server_outbuf)?;
self.state = SocksState::ReceiveResponse; self.state = SocksState::ReceiveResponse;
self.state_change() self.state_change()
} }
@ -216,6 +224,9 @@ impl SocksProxyImpl {
if response.reply != protocol::Reply::Succeeded { if response.reply != protocol::Reply::Succeeded {
return Err(format!("SOCKS connection failed: {}", response.reply).into()); return Err(format!("SOCKS connection failed: {}", response.reply).into());
} }
if self.command == protocol::Command::UdpAssociate {
self.udp_associate = Some(SocketAddr::try_from(response.address)?);
}
self.server_outbuf.append(&mut self.data_buf); self.server_outbuf.append(&mut self.data_buf);
self.data_buf.clear(); self.data_buf.clear();
@ -325,14 +336,17 @@ impl ConnectionManager for SocksProxyManager {
info.protocol == IpProtocol::Tcp info.protocol == IpProtocol::Tcp
} }
fn new_tcp_proxy(&self, info: &ConnectionInfo) -> Result<Box<dyn TcpProxy>, Error> { fn new_tcp_proxy(&self, info: &ConnectionInfo, udp_associate: bool) -> Result<Box<dyn TcpProxy>> {
if info.protocol != IpProtocol::Tcp { if info.protocol != IpProtocol::Tcp {
return Err("Invalid protocol".into()); return Err("Invalid protocol".into());
} }
use socks5_impl::protocol::Command::{Connect, UdpAssociate};
let command = if udp_associate { UdpAssociate } else { Connect };
Ok(Box::new(SocksProxyImpl::new( Ok(Box::new(SocksProxyImpl::new(
info, info,
self.credentials.clone(), self.credentials.clone(),
self.version, self.version,
command,
)?)) )?))
} }

View file

@ -193,7 +193,7 @@ pub(crate) trait UdpProxy {
pub(crate) trait ConnectionManager { pub(crate) trait ConnectionManager {
fn handles_connection(&self, info: &ConnectionInfo) -> bool; fn handles_connection(&self, info: &ConnectionInfo) -> bool;
fn new_tcp_proxy(&self, info: &ConnectionInfo) -> Result<Box<dyn TcpProxy>, Error>; fn new_tcp_proxy(&self, info: &ConnectionInfo, udp_associate: bool) -> Result<Box<dyn TcpProxy>, Error>;
fn close_connection(&self, info: &ConnectionInfo); fn close_connection(&self, info: &ConnectionInfo);
fn get_server_addr(&self) -> SocketAddr; fn get_server_addr(&self) -> SocketAddr;
fn get_credentials(&self) -> &Option<UserKey>; fn get_credentials(&self) -> &Option<UserKey>;
@ -447,7 +447,7 @@ impl<'a> TunToProxy<'a> {
if first_packet { if first_packet {
let mut done = false; let mut done = false;
for manager in self.connection_managers.iter_mut() { for manager in self.connection_managers.iter_mut() {
let tcp_proxy_handler = manager.new_tcp_proxy(&connection_info); let tcp_proxy_handler = manager.new_tcp_proxy(&connection_info, false);
if tcp_proxy_handler.is_err() { if tcp_proxy_handler.is_err() {
continue; continue;
} }
@ -504,8 +504,14 @@ impl<'a> TunToProxy<'a> {
self.expect_smoltcp_send()?; self.expect_smoltcp_send()?;
self.sockets.remove(handle); self.sockets.remove(handle);
} }
} else {
// Another UDP packet
let cm = self.get_connection_manager(&connection_info);
if cm.is_none() {
return Ok(());
}
// TODO: Handle UDP packets
} }
// Otherwise, UDP is not yet supported.
} else { } else {
log::warn!("Unsupported protocol: {} ({})", connection_info, dst); log::warn!("Unsupported protocol: {} ({})", connection_info, dst);
} }