mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
fix conflicts
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
||||
path::{Path, PathBuf},
|
||||
sync::{Arc, Mutex, RwLock},
|
||||
time::SystemTime,
|
||||
@@ -511,8 +511,12 @@ impl Config {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_any_listen_addr() -> SocketAddr {
|
||||
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0)
|
||||
pub fn get_any_listen_addr(is_ipv4: bool) -> SocketAddr {
|
||||
if is_ipv4 {
|
||||
SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)
|
||||
} else {
|
||||
SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rendezvous_server() -> String {
|
||||
@@ -993,6 +997,8 @@ pub struct LocalConfig {
|
||||
#[serde(default)]
|
||||
remote_id: String, // latest used one
|
||||
#[serde(default)]
|
||||
kb_layout_type: String,
|
||||
#[serde(default)]
|
||||
size: Size,
|
||||
#[serde(default)]
|
||||
pub fav: Vec<String>,
|
||||
@@ -1012,6 +1018,16 @@ impl LocalConfig {
|
||||
Config::store_(self, "_local");
|
||||
}
|
||||
|
||||
pub fn get_kb_layout_type() -> String {
|
||||
LOCAL_CONFIG.read().unwrap().kb_layout_type.clone()
|
||||
}
|
||||
|
||||
pub fn set_kb_layout_type(kb_layout_type: String) {
|
||||
let mut config = LOCAL_CONFIG.write().unwrap();
|
||||
config.kb_layout_type = kb_layout_type;
|
||||
config.store();
|
||||
}
|
||||
|
||||
pub fn get_size() -> Size {
|
||||
LOCAL_CONFIG.read().unwrap().size
|
||||
}
|
||||
|
||||
@@ -578,7 +578,7 @@ impl TransferJob {
|
||||
///
|
||||
/// [`Note`]
|
||||
/// Conditions:
|
||||
/// 1. Files are not waiting for comfirmation by peers.
|
||||
/// 1. Files are not waiting for confirmation by peers.
|
||||
#[inline]
|
||||
pub fn job_completed(&self) -> bool {
|
||||
// has no error, Condition 2
|
||||
|
||||
@@ -10,7 +10,7 @@ pub use protos::rendezvous as rendezvous_proto;
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{self, BufRead},
|
||||
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||
path::Path,
|
||||
time::{self, SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
@@ -67,6 +67,21 @@ macro_rules! allow_err {
|
||||
} else {
|
||||
}
|
||||
};
|
||||
|
||||
($e:expr, $($arg:tt)*) => {
|
||||
if let Err(err) = $e {
|
||||
log::debug!(
|
||||
"{:?}, {}, {}:{}:{}:{}",
|
||||
err,
|
||||
format_args!($($arg)*),
|
||||
module_path!(),
|
||||
file!(),
|
||||
line!(),
|
||||
column!()
|
||||
);
|
||||
} else {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -103,13 +118,31 @@ impl AddrMangle {
|
||||
}
|
||||
bytes[..(16 - n_padding)].to_vec()
|
||||
}
|
||||
_ => {
|
||||
panic!("Only support ipv4");
|
||||
SocketAddr::V6(addr_v6) => {
|
||||
let mut x = addr_v6.ip().octets().to_vec();
|
||||
let port: [u8; 2] = addr_v6.port().to_le_bytes();
|
||||
x.push(port[0]);
|
||||
x.push(port[1]);
|
||||
x
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode(bytes: &[u8]) -> SocketAddr {
|
||||
if bytes.len() > 16 {
|
||||
if bytes.len() != 18 {
|
||||
return Config::get_any_listen_addr(false);
|
||||
}
|
||||
#[allow(invalid_value)]
|
||||
let mut tmp: [u8; 2] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
|
||||
tmp.copy_from_slice(&bytes[16..]);
|
||||
let port = u16::from_le_bytes(tmp);
|
||||
#[allow(invalid_value)]
|
||||
let mut tmp: [u8; 16] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
|
||||
tmp.copy_from_slice(&bytes[..16]);
|
||||
let ip = std::net::Ipv6Addr::from(tmp);
|
||||
return SocketAddr::new(IpAddr::V6(ip), port);
|
||||
}
|
||||
let mut padded = [0u8; 16];
|
||||
padded[..bytes.len()].copy_from_slice(&bytes);
|
||||
let number = u128::from_le_bytes(padded);
|
||||
@@ -250,5 +283,61 @@ mod tests {
|
||||
fn test_mangle() {
|
||||
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 16, 32), 21116));
|
||||
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
|
||||
|
||||
let addr = "[2001:db8::1]:8080".parse::<SocketAddr>().unwrap();
|
||||
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
|
||||
|
||||
let addr = "[2001:db8:ff::1111]:80".parse::<SocketAddr>().unwrap();
|
||||
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_allow_err() {
|
||||
allow_err!(Err("test err") as Result<(), &str>);
|
||||
allow_err!(
|
||||
Err("test err with msg") as Result<(), &str>,
|
||||
"prompt {}",
|
||||
"failed"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_ipv4_str(id: &str) -> bool {
|
||||
regex::Regex::new(r"^\d+\.\d+\.\d+\.\d+(:\d+)?$")
|
||||
.unwrap()
|
||||
.is_match(id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_ipv6_str(id: &str) -> bool {
|
||||
regex::Regex::new(r"^((([a-fA-F0-9]{1,4}:{1,2})+[a-fA-F0-9]{1,4})|(\[([a-fA-F0-9]{1,4}:{1,2})+[a-fA-F0-9]{1,4}\]:\d+))$")
|
||||
.unwrap()
|
||||
.is_match(id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_ip_str(id: &str) -> bool {
|
||||
is_ipv4_str(id) || is_ipv6_str(id)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_lib {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_ipv6() {
|
||||
assert_eq!(is_ipv6_str("1:2:3"), true);
|
||||
assert_eq!(is_ipv6_str("[ab:2:3]:12"), true);
|
||||
assert_eq!(is_ipv6_str("[ABEF:2a:3]:12"), true);
|
||||
assert_eq!(is_ipv6_str("[ABEG:2a:3]:12"), false);
|
||||
assert_eq!(is_ipv6_str("1[ab:2:3]:12"), false);
|
||||
assert_eq!(is_ipv6_str("1.1.1.1"), false);
|
||||
assert_eq!(is_ip_str("1.1.1.1"), true);
|
||||
assert_eq!(is_ipv6_str("1:2:"), false);
|
||||
assert_eq!(is_ipv6_str("1:2::0"), true);
|
||||
assert_eq!(is_ipv6_str("[1:2::0]:1"), true);
|
||||
assert_eq!(is_ipv6_str("[1:2::0]:"), false);
|
||||
assert_eq!(is_ipv6_str("1:2::0]:1"), false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
use crate::ResultType;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref DISTRO: Disto = Disto::new();
|
||||
pub static ref DISTRO: Distro = Distro::new();
|
||||
}
|
||||
|
||||
pub struct Disto {
|
||||
pub struct Distro {
|
||||
pub name: String,
|
||||
pub version_id: String,
|
||||
}
|
||||
|
||||
impl Disto {
|
||||
impl Distro {
|
||||
fn new() -> Self {
|
||||
let name = run_cmds("awk -F'=' '/^NAME=/ {print $2}' /etc/os-release".to_owned())
|
||||
.unwrap_or_default()
|
||||
@@ -74,7 +74,7 @@ fn get_display_server_of_session(session: &str) -> String {
|
||||
} else {
|
||||
"".to_owned()
|
||||
};
|
||||
if display_server.is_empty() {
|
||||
if display_server.is_empty() || display_server == "tty" {
|
||||
// loginctl has not given the expected output. try something else.
|
||||
if let Ok(sestype) = std::env::var("XDG_SESSION_TYPE") {
|
||||
display_server = sestype;
|
||||
|
||||
@@ -9,31 +9,52 @@ use std::net::SocketAddr;
|
||||
use tokio::net::ToSocketAddrs;
|
||||
use tokio_socks::{IntoTargetAddr, TargetAddr};
|
||||
|
||||
fn to_socket_addr(host: &str) -> ResultType<SocketAddr> {
|
||||
use std::net::ToSocketAddrs;
|
||||
host.to_socket_addrs()?
|
||||
.filter(|x| x.is_ipv4())
|
||||
.next()
|
||||
.context("Failed to solve")
|
||||
#[inline]
|
||||
pub fn check_port<T: std::string::ToString>(host: T, port: i32) -> String {
|
||||
let host = host.to_string();
|
||||
if crate::is_ipv6_str(&host) {
|
||||
if host.starts_with("[") {
|
||||
return host;
|
||||
}
|
||||
return format!("[{}]:{}", host, port);
|
||||
}
|
||||
if !host.contains(":") {
|
||||
return format!("{}:{}", host, port);
|
||||
}
|
||||
return host;
|
||||
}
|
||||
|
||||
pub fn get_target_addr(host: &str) -> ResultType<TargetAddr<'static>> {
|
||||
let addr = match Config::get_network_type() {
|
||||
NetworkType::Direct => to_socket_addr(&host)?.into_target_addr()?,
|
||||
NetworkType::ProxySocks => host.into_target_addr()?,
|
||||
#[inline]
|
||||
pub fn increase_port<T: std::string::ToString>(host: T, offset: i32) -> String {
|
||||
let host = host.to_string();
|
||||
if crate::is_ipv6_str(&host) {
|
||||
if host.starts_with("[") {
|
||||
let tmp: Vec<&str> = host.split("]:").collect();
|
||||
if tmp.len() == 2 {
|
||||
let port: i32 = tmp[1].parse().unwrap_or(0);
|
||||
if port > 0 {
|
||||
return format!("{}]:{}", tmp[0], port + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if host.contains(":") {
|
||||
let tmp: Vec<&str> = host.split(":").collect();
|
||||
if tmp.len() == 2 {
|
||||
let port: i32 = tmp[1].parse().unwrap_or(0);
|
||||
if port > 0 {
|
||||
return format!("{}:{}", tmp[0], port + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
.to_owned();
|
||||
Ok(addr)
|
||||
return host;
|
||||
}
|
||||
|
||||
pub fn test_if_valid_server(host: &str) -> String {
|
||||
let mut host = host.to_owned();
|
||||
if !host.contains(":") {
|
||||
host = format!("{}:{}", host, 0);
|
||||
}
|
||||
let host = check_port(host, 0);
|
||||
|
||||
use std::net::ToSocketAddrs;
|
||||
match Config::get_network_type() {
|
||||
NetworkType::Direct => match to_socket_addr(&host) {
|
||||
NetworkType::Direct => match host.to_socket_addrs() {
|
||||
Err(err) => err.to_string(),
|
||||
Ok(_) => "".to_owned(),
|
||||
},
|
||||
@@ -44,33 +65,126 @@ pub fn test_if_valid_server(host: &str) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn connect_tcp<'t, T: IntoTargetAddr<'t>>(
|
||||
pub trait IsResolvedSocketAddr {
|
||||
fn resolve(&self) -> Option<&SocketAddr>;
|
||||
}
|
||||
|
||||
impl IsResolvedSocketAddr for SocketAddr {
|
||||
fn resolve(&self) -> Option<&SocketAddr> {
|
||||
Some(&self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsResolvedSocketAddr for String {
|
||||
fn resolve(&self) -> Option<&SocketAddr> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl IsResolvedSocketAddr for &str {
|
||||
fn resolve(&self) -> Option<&SocketAddr> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn connect_tcp<
|
||||
't,
|
||||
T: IntoTargetAddr<'t> + ToSocketAddrs + IsResolvedSocketAddr + std::fmt::Display,
|
||||
>(
|
||||
target: T,
|
||||
local: SocketAddr,
|
||||
ms_timeout: u64,
|
||||
) -> ResultType<FramedStream> {
|
||||
let target_addr = target.into_target_addr()?;
|
||||
connect_tcp_local(target, None, ms_timeout).await
|
||||
}
|
||||
|
||||
pub async fn connect_tcp_local<
|
||||
't,
|
||||
T: IntoTargetAddr<'t> + ToSocketAddrs + IsResolvedSocketAddr + std::fmt::Display,
|
||||
>(
|
||||
target: T,
|
||||
local: Option<SocketAddr>,
|
||||
ms_timeout: u64,
|
||||
) -> ResultType<FramedStream> {
|
||||
if let Some(conf) = Config::get_socks() {
|
||||
FramedStream::connect(
|
||||
return FramedStream::connect(
|
||||
conf.proxy.as_str(),
|
||||
target_addr,
|
||||
target,
|
||||
local,
|
||||
conf.username.as_str(),
|
||||
conf.password.as_str(),
|
||||
ms_timeout,
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
let addr = std::net::ToSocketAddrs::to_socket_addrs(&target_addr)?
|
||||
.filter(|x| x.is_ipv4())
|
||||
.next()
|
||||
.context("Invalid target addr, no valid ipv4 address can be resolved.")?;
|
||||
Ok(FramedStream::new(addr, local, ms_timeout).await?)
|
||||
.await;
|
||||
}
|
||||
if let Some(target) = target.resolve() {
|
||||
if let Some(local) = local {
|
||||
if local.is_ipv6() && target.is_ipv4() {
|
||||
let target = query_nip_io(&target).await?;
|
||||
return Ok(FramedStream::new(target, Some(local), ms_timeout).await?);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(FramedStream::new(target, local, ms_timeout).await?)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_ipv4(target: &TargetAddr<'_>) -> bool {
|
||||
match target {
|
||||
TargetAddr::Ip(addr) => addr.is_ipv4(),
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn new_udp<T: ToSocketAddrs>(local: T, ms_timeout: u64) -> ResultType<FramedSocket> {
|
||||
#[inline]
|
||||
pub async fn query_nip_io(addr: &SocketAddr) -> ResultType<SocketAddr> {
|
||||
tokio::net::lookup_host(format!("{}.nip.io:{}", addr.ip(), addr.port()))
|
||||
.await?
|
||||
.filter(|x| x.is_ipv6())
|
||||
.next()
|
||||
.context("Failed to get ipv6 from nip.io")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ipv4_to_ipv6(addr: String, ipv4: bool) -> String {
|
||||
if !ipv4 && crate::is_ipv4_str(&addr) {
|
||||
if let Some(ip) = addr.split(":").next() {
|
||||
return addr.replace(ip, &format!("{}.nip.io", ip));
|
||||
}
|
||||
}
|
||||
addr
|
||||
}
|
||||
|
||||
async fn test_target(target: &str) -> ResultType<SocketAddr> {
|
||||
if let Ok(Ok(s)) = super::timeout(1000, tokio::net::TcpStream::connect(target)).await {
|
||||
if let Ok(addr) = s.peer_addr() {
|
||||
return Ok(addr);
|
||||
}
|
||||
}
|
||||
tokio::net::lookup_host(target)
|
||||
.await?
|
||||
.next()
|
||||
.context(format!("Failed to look up host for {}", target))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn new_udp_for(
|
||||
target: &str,
|
||||
ms_timeout: u64,
|
||||
) -> ResultType<(FramedSocket, TargetAddr<'static>)> {
|
||||
let (ipv4, target) = if NetworkType::Direct == Config::get_network_type() {
|
||||
let addr = test_target(target).await?;
|
||||
(addr.is_ipv4(), addr.into_target_addr()?)
|
||||
} else {
|
||||
(true, target.into_target_addr()?)
|
||||
};
|
||||
Ok((
|
||||
new_udp(Config::get_any_listen_addr(ipv4), ms_timeout).await?,
|
||||
target.to_owned(),
|
||||
))
|
||||
}
|
||||
|
||||
async fn new_udp<T: ToSocketAddrs>(local: T, ms_timeout: u64) -> ResultType<FramedSocket> {
|
||||
match Config::get_socks() {
|
||||
None => Ok(FramedSocket::new(local).await?),
|
||||
Some(conf) => {
|
||||
@@ -87,9 +201,82 @@ pub async fn new_udp<T: ToSocketAddrs>(local: T, ms_timeout: u64) -> ResultType<
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn rebind_udp<T: ToSocketAddrs>(local: T) -> ResultType<Option<FramedSocket>> {
|
||||
match Config::get_network_type() {
|
||||
NetworkType::Direct => Ok(Some(FramedSocket::new(local).await?)),
|
||||
_ => Ok(None),
|
||||
pub async fn rebind_udp_for(
|
||||
target: &str,
|
||||
) -> ResultType<Option<(FramedSocket, TargetAddr<'static>)>> {
|
||||
if Config::get_network_type() != NetworkType::Direct {
|
||||
return Ok(None);
|
||||
}
|
||||
let addr = test_target(target).await?;
|
||||
let v4 = addr.is_ipv4();
|
||||
Ok(Some((
|
||||
FramedSocket::new(Config::get_any_listen_addr(v4)).await?,
|
||||
addr.into_target_addr()?.to_owned(),
|
||||
)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::net::ToSocketAddrs;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_nat64() {
|
||||
test_nat64_async();
|
||||
}
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn test_nat64_async() {
|
||||
assert_eq!(ipv4_to_ipv6("1.1.1.1".to_owned(), true), "1.1.1.1");
|
||||
assert_eq!(ipv4_to_ipv6("1.1.1.1".to_owned(), false), "1.1.1.1.nip.io");
|
||||
assert_eq!(
|
||||
ipv4_to_ipv6("1.1.1.1:8080".to_owned(), false),
|
||||
"1.1.1.1.nip.io:8080"
|
||||
);
|
||||
assert_eq!(
|
||||
ipv4_to_ipv6("rustdesk.com".to_owned(), false),
|
||||
"rustdesk.com"
|
||||
);
|
||||
if ("rustdesk.com:80")
|
||||
.to_socket_addrs()
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap()
|
||||
.is_ipv6()
|
||||
{
|
||||
assert!(query_nip_io(&"1.1.1.1:80".parse().unwrap())
|
||||
.await
|
||||
.unwrap()
|
||||
.is_ipv6());
|
||||
return;
|
||||
}
|
||||
assert!(query_nip_io(&"1.1.1.1:80".parse().unwrap()).await.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_test_if_valid_server() {
|
||||
assert!(!test_if_valid_server("a").is_empty());
|
||||
// on Linux, "1" is resolved to "0.0.0.1"
|
||||
assert!(test_if_valid_server("1.1.1.1").is_empty());
|
||||
assert!(test_if_valid_server("1.1.1.1:1").is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_port() {
|
||||
assert_eq!(check_port("[1:2]:12", 32), "[1:2]:12");
|
||||
assert_eq!(check_port("1:2", 32), "[1:2]:32");
|
||||
assert_eq!(check_port("z1:2", 32), "z1:2");
|
||||
assert_eq!(check_port("1.1.1.1", 32), "1.1.1.1:32");
|
||||
assert_eq!(check_port("1.1.1.1:32", 32), "1.1.1.1:32");
|
||||
assert_eq!(check_port("test.com:32", 0), "test.com:32");
|
||||
assert_eq!(increase_port("[1:2]:12", 1), "[1:2]:13");
|
||||
assert_eq!(increase_port("1.2.2.4:12", 1), "1.2.2.4:13");
|
||||
assert_eq!(increase_port("1.2.2.4", 1), "1.2.2.4");
|
||||
assert_eq!(increase_port("test.com", 1), "test.com");
|
||||
assert_eq!(increase_port("test.com:13", 4), "test.com:17");
|
||||
assert_eq!(increase_port("1:13", 4), "1:13");
|
||||
assert_eq!(increase_port("22:1:13", 4), "22:1:13");
|
||||
assert_eq!(increase_port("z1:2", 1), "z1:3");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use protobuf::Message;
|
||||
use sodiumoxide::crypto::secretbox::{self, Key, Nonce};
|
||||
use std::{
|
||||
io::{self, Error, ErrorKind},
|
||||
net::SocketAddr,
|
||||
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
||||
ops::{Deref, DerefMut},
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
@@ -73,73 +73,79 @@ fn new_socket(addr: std::net::SocketAddr, reuse: bool) -> Result<TcpSocket, std:
|
||||
}
|
||||
|
||||
impl FramedStream {
|
||||
pub async fn new<T1: ToSocketAddrs, T2: ToSocketAddrs>(
|
||||
remote_addr: T1,
|
||||
local_addr: T2,
|
||||
pub async fn new<T: ToSocketAddrs + std::fmt::Display>(
|
||||
remote_addr: T,
|
||||
local_addr: Option<SocketAddr>,
|
||||
ms_timeout: u64,
|
||||
) -> ResultType<Self> {
|
||||
for local_addr in lookup_host(&local_addr).await? {
|
||||
for remote_addr in lookup_host(&remote_addr).await? {
|
||||
let stream = super::timeout(
|
||||
ms_timeout,
|
||||
new_socket(local_addr, true)?.connect(remote_addr),
|
||||
)
|
||||
.await??;
|
||||
stream.set_nodelay(true).ok();
|
||||
let addr = stream.local_addr()?;
|
||||
return Ok(Self(
|
||||
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
|
||||
addr,
|
||||
None,
|
||||
0,
|
||||
));
|
||||
for remote_addr in lookup_host(&remote_addr).await? {
|
||||
let local = if let Some(addr) = local_addr {
|
||||
addr
|
||||
} else {
|
||||
crate::config::Config::get_any_listen_addr(remote_addr.is_ipv4())
|
||||
};
|
||||
if let Ok(socket) = new_socket(local, true) {
|
||||
if let Ok(Ok(stream)) =
|
||||
super::timeout(ms_timeout, socket.connect(remote_addr)).await
|
||||
{
|
||||
stream.set_nodelay(true).ok();
|
||||
let addr = stream.local_addr()?;
|
||||
return Ok(Self(
|
||||
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
|
||||
addr,
|
||||
None,
|
||||
0,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
bail!("could not resolve to any address");
|
||||
bail!(format!("Failed to connect to {}", remote_addr));
|
||||
}
|
||||
|
||||
pub async fn connect<'a, 't, P, T1, T2>(
|
||||
pub async fn connect<'a, 't, P, T>(
|
||||
proxy: P,
|
||||
target: T1,
|
||||
local: T2,
|
||||
target: T,
|
||||
local_addr: Option<SocketAddr>,
|
||||
username: &'a str,
|
||||
password: &'a str,
|
||||
ms_timeout: u64,
|
||||
) -> ResultType<Self>
|
||||
where
|
||||
P: ToProxyAddrs,
|
||||
T1: IntoTargetAddr<'t>,
|
||||
T2: ToSocketAddrs,
|
||||
T: IntoTargetAddr<'t>,
|
||||
{
|
||||
if let Some(local) = lookup_host(&local).await?.next() {
|
||||
if let Some(proxy) = proxy.to_proxy_addrs().next().await {
|
||||
let stream =
|
||||
super::timeout(ms_timeout, new_socket(local, true)?.connect(proxy?)).await??;
|
||||
stream.set_nodelay(true).ok();
|
||||
let stream = if username.trim().is_empty() {
|
||||
super::timeout(
|
||||
ms_timeout,
|
||||
Socks5Stream::connect_with_socket(stream, target),
|
||||
)
|
||||
.await??
|
||||
} else {
|
||||
super::timeout(
|
||||
ms_timeout,
|
||||
Socks5Stream::connect_with_password_and_socket(
|
||||
stream, target, username, password,
|
||||
),
|
||||
)
|
||||
.await??
|
||||
};
|
||||
let addr = stream.local_addr()?;
|
||||
return Ok(Self(
|
||||
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
|
||||
addr,
|
||||
None,
|
||||
0,
|
||||
));
|
||||
if let Some(Ok(proxy)) = proxy.to_proxy_addrs().next().await {
|
||||
let local = if let Some(addr) = local_addr {
|
||||
addr
|
||||
} else {
|
||||
crate::config::Config::get_any_listen_addr(proxy.is_ipv4())
|
||||
};
|
||||
};
|
||||
let stream =
|
||||
super::timeout(ms_timeout, new_socket(local, true)?.connect(proxy)).await??;
|
||||
stream.set_nodelay(true).ok();
|
||||
let stream = if username.trim().is_empty() {
|
||||
super::timeout(
|
||||
ms_timeout,
|
||||
Socks5Stream::connect_with_socket(stream, target),
|
||||
)
|
||||
.await??
|
||||
} else {
|
||||
super::timeout(
|
||||
ms_timeout,
|
||||
Socks5Stream::connect_with_password_and_socket(
|
||||
stream, target, username, password,
|
||||
),
|
||||
)
|
||||
.await??
|
||||
};
|
||||
let addr = stream.local_addr()?;
|
||||
return Ok(Self(
|
||||
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
|
||||
addr,
|
||||
None,
|
||||
0,
|
||||
));
|
||||
}
|
||||
bail!("could not resolve to any address");
|
||||
}
|
||||
|
||||
@@ -252,6 +258,38 @@ pub async fn new_listener<T: ToSocketAddrs>(addr: T, reuse: bool) -> ResultType<
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn listen_any(port: u16) -> ResultType<TcpListener> {
|
||||
if let Ok(mut socket) = TcpSocket::new_v6() {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::io::{FromRawFd, IntoRawFd};
|
||||
let raw_fd = socket.into_raw_fd();
|
||||
let sock2 = unsafe { socket2::Socket::from_raw_fd(raw_fd) };
|
||||
sock2.set_only_v6(false).ok();
|
||||
socket = unsafe { TcpSocket::from_raw_fd(sock2.into_raw_fd()) };
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::os::windows::prelude::{FromRawSocket, IntoRawSocket};
|
||||
let raw_socket = socket.into_raw_socket();
|
||||
let sock2 = unsafe { socket2::Socket::from_raw_socket(raw_socket) };
|
||||
sock2.set_only_v6(false).ok();
|
||||
socket = unsafe { TcpSocket::from_raw_socket(sock2.into_raw_socket()) };
|
||||
}
|
||||
if socket
|
||||
.bind(SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), port))
|
||||
.is_ok()
|
||||
{
|
||||
if let Ok(l) = socket.listen(DEFAULT_BACKLOG) {
|
||||
return Ok(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
let s = TcpSocket::new_v4()?;
|
||||
s.bind(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), port))?;
|
||||
Ok(s.listen(DEFAULT_BACKLOG)?)
|
||||
}
|
||||
|
||||
impl Unpin for DynTcpStream {}
|
||||
|
||||
impl AsyncRead for DynTcpStream {
|
||||
|
||||
@@ -49,7 +49,7 @@ impl FramedSocket {
|
||||
|
||||
#[allow(clippy::never_loop)]
|
||||
pub async fn new_reuse<T: std::net::ToSocketAddrs>(addr: T) -> ResultType<Self> {
|
||||
for addr in addr.to_socket_addrs()?.filter(|x| x.is_ipv4()) {
|
||||
for addr in addr.to_socket_addrs()? {
|
||||
let socket = new_socket(addr, true, 0)?.into_udp_socket();
|
||||
return Ok(Self::Direct(UdpFramed::new(
|
||||
UdpSocket::from_std(socket)?,
|
||||
@@ -63,7 +63,7 @@ impl FramedSocket {
|
||||
addr: T,
|
||||
buf_size: usize,
|
||||
) -> ResultType<Self> {
|
||||
for addr in addr.to_socket_addrs()?.filter(|x| x.is_ipv4()) {
|
||||
for addr in addr.to_socket_addrs()? {
|
||||
return Ok(Self::Direct(UdpFramed::new(
|
||||
UdpSocket::from_std(new_socket(addr, false, buf_size)?.into_udp_socket())?,
|
||||
BytesCodec::new(),
|
||||
@@ -164,4 +164,13 @@ impl FramedSocket {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_ipv4(&self) -> bool {
|
||||
if let FramedSocket::Direct(x) = self {
|
||||
if let Ok(v) = x.get_ref().local_addr() {
|
||||
return v.is_ipv4();
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user