mirror of
https://github.com/shadowsocks/shadowsocks-rust.git
synced 2026-02-09 01:59:16 +08:00
redir local converts IPv4-mapped IPv6 addresses to IPv4
- Dual-stack IPv6 will always return destination addresses in IPv4-mapped IPv6 addresses
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
//! Shadowsocks Local Transparent Proxy
|
||||
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
|
||||
pub use self::server::Redir;
|
||||
|
||||
mod redir_ext;
|
||||
@@ -7,3 +9,13 @@ mod server;
|
||||
mod sys;
|
||||
mod tcprelay;
|
||||
mod udprelay;
|
||||
|
||||
/// Helper function for converting IPv4 mapped IPv6 address
|
||||
///
|
||||
/// This is the same as `Ipv6Addr::to_ipv4_mapped`, but it is still unstable in the current libstd
|
||||
fn to_ipv4_mapped(ipv6: &Ipv6Addr) -> Option<Ipv4Addr> {
|
||||
match ipv6.octets() {
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => Some(Ipv4Addr::new(a, b, c, d)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
//! Shadowsocks TCP transparent proxy
|
||||
|
||||
use std::{io, net::SocketAddr, sync::Arc, time::Duration};
|
||||
use std::{
|
||||
io,
|
||||
net::{IpAddr, SocketAddr},
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use log::{debug, error, info, trace};
|
||||
use shadowsocks::{lookup_then, net::TcpListener as ShadowTcpListener, relay::socks5::Address};
|
||||
@@ -15,7 +20,10 @@ use crate::{
|
||||
context::ServiceContext,
|
||||
loadbalancing::PingBalancer,
|
||||
net::{AutoProxyClientStream, AutoProxyIo},
|
||||
redir::redir_ext::{TcpListenerRedirExt, TcpStreamRedirExt},
|
||||
redir::{
|
||||
redir_ext::{TcpListenerRedirExt, TcpStreamRedirExt},
|
||||
to_ipv4_mapped,
|
||||
},
|
||||
utils::establish_tcp_tunnel,
|
||||
},
|
||||
};
|
||||
@@ -74,7 +82,7 @@ async fn handle_redir_client(
|
||||
balancer: PingBalancer,
|
||||
s: TcpStream,
|
||||
peer_addr: SocketAddr,
|
||||
daddr: SocketAddr,
|
||||
mut daddr: SocketAddr,
|
||||
nodelay: bool,
|
||||
) -> io::Result<()> {
|
||||
// let svr_cfg = server.server_config();
|
||||
@@ -90,6 +98,13 @@ async fn handle_redir_client(
|
||||
}
|
||||
|
||||
// Get forward address from socket
|
||||
//
|
||||
// Try to convert IPv4 mapped IPv6 address for dual-stack mode.
|
||||
if let SocketAddr::V6(ref a) = daddr {
|
||||
if let Some(v4) = to_ipv4_mapped(a.ip()) {
|
||||
daddr = SocketAddr::new(IpAddr::from(v4), a.port());
|
||||
}
|
||||
}
|
||||
let target_addr = Address::from(daddr);
|
||||
establish_client_tcp_redir(context, balancer, s, peer_addr, &target_addr, nodelay).await
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use std::{
|
||||
io::{self, ErrorKind},
|
||||
net::SocketAddr,
|
||||
net::{IpAddr, SocketAddr},
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
@@ -20,7 +20,10 @@ use crate::{
|
||||
context::ServiceContext,
|
||||
loadbalancing::PingBalancer,
|
||||
net::{UdpAssociationManager, UdpInboundWrite},
|
||||
redir::redir_ext::{RedirSocketOpts, UdpSocketRedirExt},
|
||||
redir::{
|
||||
redir_ext::{RedirSocketOpts, UdpSocketRedirExt},
|
||||
to_ipv4_mapped,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -38,7 +41,16 @@ struct UdpRedirInboundWriter {
|
||||
impl UdpInboundWrite for UdpRedirInboundWriter {
|
||||
async fn send_to(&self, peer_addr: SocketAddr, remote_addr: &Address, data: &[u8]) -> io::Result<()> {
|
||||
let addr = match *remote_addr {
|
||||
Address::SocketAddress(sa) => sa,
|
||||
Address::SocketAddress(sa) => {
|
||||
// Try to convert IPv4 mapped IPv6 address if server is running on dual-stack mode
|
||||
match sa {
|
||||
SocketAddr::V4(..) => sa,
|
||||
SocketAddr::V6(ref v6) => match to_ipv4_mapped(v6.ip()) {
|
||||
Some(v4) => SocketAddr::new(IpAddr::from(v4), v6.port()),
|
||||
None => sa,
|
||||
},
|
||||
}
|
||||
}
|
||||
Address::DomainNameAddress(..) => {
|
||||
let err = io::Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
@@ -132,7 +144,7 @@ impl UdpRedir {
|
||||
|
||||
let mut pkt_buf = [0u8; MAXIMUM_UDP_PAYLOAD_SIZE];
|
||||
loop {
|
||||
let (recv_len, src, dst) = match listener.recv_dest_from(&mut pkt_buf).await {
|
||||
let (recv_len, src, mut dst) = match listener.recv_dest_from(&mut pkt_buf).await {
|
||||
Ok(o) => o,
|
||||
Err(err) => {
|
||||
error!("recv_dest_from failed with err: {}", err);
|
||||
@@ -162,6 +174,13 @@ impl UdpRedir {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try to convert IPv4 mapped IPv6 address for dual-stack mode.
|
||||
if let SocketAddr::V6(ref a) = dst {
|
||||
if let Some(v4) = to_ipv4_mapped(a.ip()) {
|
||||
dst = SocketAddr::new(IpAddr::from(v4), a.port());
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(err) = manager.send_to(src, Address::from(dst), pkt).await {
|
||||
error!(
|
||||
"udp packet relay {} -> {} with {} bytes failed, error: {}",
|
||||
|
||||
Reference in New Issue
Block a user