通过stun探测端口,解决使用ipv6或tcp服务时端口错误的问题
This commit is contained in:
@@ -339,6 +339,7 @@ pub fn start<Call: VntCallback>(
|
||||
context.clone(),
|
||||
current_device.clone(),
|
||||
server_cipher.clone(),
|
||||
nat_test.clone(),
|
||||
config_info.clone(),
|
||||
);
|
||||
// 定时打洞
|
||||
@@ -420,4 +421,7 @@ impl Vnt {
|
||||
pub fn wait_timeout(&self, dur: Duration) -> bool {
|
||||
self.stop_manager.wait_timeout(dur)
|
||||
}
|
||||
pub fn config(&self) -> &Config {
|
||||
&self.config
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,10 @@ use std::time::Duration;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
|
||||
use crate::channel::context::ChannelContext;
|
||||
use crate::channel::punch::NatType;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::handle::{BaseConfigInfo, CurrentDeviceInfo};
|
||||
use crate::nat::NatTest;
|
||||
use crate::protocol::body::ENCRYPTION_RESERVED;
|
||||
use crate::protocol::{control_packet, NetPacket, Protocol, MAX_TTL};
|
||||
use crate::util::Scheduler;
|
||||
@@ -15,6 +17,7 @@ pub fn addr_request(
|
||||
context: ChannelContext,
|
||||
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
server_cipher: Cipher,
|
||||
nat_test: NatTest,
|
||||
_config: BaseConfigInfo,
|
||||
) {
|
||||
pub_address_request(
|
||||
@@ -22,31 +25,67 @@ pub fn addr_request(
|
||||
context,
|
||||
current_device_info.clone(),
|
||||
server_cipher,
|
||||
nat_test,
|
||||
0,
|
||||
);
|
||||
}
|
||||
pub fn pub_address_request(
|
||||
|
||||
fn pub_address_request(
|
||||
scheduler: &Scheduler,
|
||||
context: ChannelContext,
|
||||
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
server_cipher: Cipher,
|
||||
nat_test: NatTest,
|
||||
count: usize,
|
||||
) {
|
||||
addr_request0(&context, ¤t_device_info, &server_cipher);
|
||||
// 9秒发送一次
|
||||
let rs = scheduler.timeout(Duration::from_secs(9), |s| {
|
||||
pub_address_request(s, context, current_device_info, server_cipher)
|
||||
let channel_num = context.channel_num();
|
||||
let index = count % channel_num;
|
||||
let mut time = if index == channel_num - 1 { 19 } else { 1 };
|
||||
if let Err(e) = addr_request0(
|
||||
&context,
|
||||
¤t_device_info,
|
||||
&server_cipher,
|
||||
&nat_test,
|
||||
index,
|
||||
) {
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
let nat_info = nat_test.nat_info();
|
||||
if nat_info.nat_type == NatType::Symmetric {
|
||||
//对称网络探测端口没啥作用,把频率放低,(锥形网络也只在打洞前需要探测端口,后续可以改改)
|
||||
if !nat_info.public_ports.contains(&0) && !nat_info.public_ips.is_empty() {
|
||||
time = 600;
|
||||
}
|
||||
}
|
||||
|
||||
let rs = scheduler.timeout(Duration::from_secs(time), move |s| {
|
||||
pub_address_request(
|
||||
s,
|
||||
context,
|
||||
current_device_info,
|
||||
server_cipher,
|
||||
nat_test,
|
||||
index + 1,
|
||||
)
|
||||
});
|
||||
if !rs {
|
||||
log::info!("定时任务停止");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addr_request0(
|
||||
fn addr_request0(
|
||||
context: &ChannelContext,
|
||||
current_device: &AtomicCell<CurrentDeviceInfo>,
|
||||
server_cipher: &Cipher,
|
||||
) {
|
||||
nat_test: &NatTest,
|
||||
index: usize,
|
||||
) -> anyhow::Result<()> {
|
||||
let current_dev = current_device.load();
|
||||
if current_dev.connect_server.is_ipv4() && current_dev.status.online() {
|
||||
if current_dev.status.offline() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if current_dev.connect_server.is_ipv4() && !context.is_main_tcp() {
|
||||
// 如果连接的是ipv4服务,则探测公网端口
|
||||
let gateway_ip = current_dev.virtual_gateway;
|
||||
let src_ip = current_dev.virtual_ip;
|
||||
@@ -58,10 +97,11 @@ pub fn addr_request0(
|
||||
packet.first_set_ttl(MAX_TTL);
|
||||
packet.set_source(src_ip);
|
||||
packet.set_destination(gateway_ip);
|
||||
if let Err(e) = server_cipher.encrypt_ipv4(&mut packet) {
|
||||
log::warn!("AddrRequest err={:?}", e)
|
||||
} else {
|
||||
context.try_send_all_main(packet.buffer(), current_dev.connect_server);
|
||||
}
|
||||
server_cipher.encrypt_ipv4(&mut packet)?;
|
||||
context.send_main_udp(index, packet.buffer(), current_dev.connect_server)?;
|
||||
} else {
|
||||
let (data, addr) = nat_test.send_data()?;
|
||||
context.send_main_udp(index, &data, addr)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ mod re_nat_type;
|
||||
pub use re_nat_type::retrieve_nat_type;
|
||||
|
||||
mod addr_request;
|
||||
pub use addr_request::addr_request;
|
||||
pub use addr_request::*;
|
||||
|
||||
mod punch;
|
||||
pub use punch::*;
|
||||
|
||||
@@ -39,10 +39,22 @@ pub struct RecvDataHandler<Call> {
|
||||
client: ClientPacketHandler,
|
||||
server: ServerPacketHandler<Call>,
|
||||
counter: U64Adder,
|
||||
nat_test: NatTest,
|
||||
}
|
||||
|
||||
impl<Call: VntCallback> RecvChannelHandler for RecvDataHandler<Call> {
|
||||
fn handle(&mut self, buf: &mut [u8], route_key: RouteKey, context: &ChannelContext) {
|
||||
//判断stun响应包
|
||||
if !route_key.is_tcp() {
|
||||
if let Ok(rs) = self
|
||||
.nat_test
|
||||
.recv_data(route_key.index(), route_key.addr, buf)
|
||||
{
|
||||
if rs {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Err(e) = self.handle0(buf, route_key, context) {
|
||||
log::error!("[{}]-{:?}", thread::current().name().unwrap_or(""), e);
|
||||
}
|
||||
@@ -86,7 +98,7 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
|
||||
client_cipher,
|
||||
punch_sender,
|
||||
peer_nat_info_map,
|
||||
nat_test,
|
||||
nat_test.clone(),
|
||||
route,
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
ip_proxy_map,
|
||||
@@ -98,6 +110,7 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
|
||||
client,
|
||||
server,
|
||||
counter,
|
||||
nat_test,
|
||||
}
|
||||
}
|
||||
fn handle0(
|
||||
|
||||
+65
-1
@@ -1,5 +1,6 @@
|
||||
use anyhow::Context;
|
||||
use std::io;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
|
||||
use std::net::{SocketAddr, UdpSocket};
|
||||
use std::ops::Sub;
|
||||
use std::sync::Arc;
|
||||
@@ -7,6 +8,7 @@ use std::time::{Duration, Instant};
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::channel::punch::{NatInfo, NatType};
|
||||
use crate::proto::message::PunchNatType;
|
||||
@@ -202,4 +204,66 @@ impl NatTest {
|
||||
|
||||
Ok(guard.clone())
|
||||
}
|
||||
pub fn send_data(&self) -> anyhow::Result<(Vec<u8>, SocketAddr)> {
|
||||
let len = self.stun_server.len();
|
||||
let stun_server = if len == 1 {
|
||||
&self.stun_server[0]
|
||||
} else {
|
||||
let index = rand::thread_rng().gen_range(0..self.stun_server.len());
|
||||
&self.stun_server[index]
|
||||
};
|
||||
let addr = stun_server
|
||||
.to_socket_addrs()?
|
||||
.next()
|
||||
.with_context(|| format!("stun error {:?}", stun_server))?;
|
||||
Ok((stun::send_stun_request(), addr))
|
||||
}
|
||||
pub fn recv_data(
|
||||
&self,
|
||||
index: usize,
|
||||
source_addr: SocketAddr,
|
||||
buf: &[u8],
|
||||
) -> anyhow::Result<bool> {
|
||||
if let Some(addr) = stun::recv_stun_response(buf) {
|
||||
if let SocketAddr::V4(addr) = addr {
|
||||
let mut check_fail = true;
|
||||
let source_ip = match source_addr.ip() {
|
||||
IpAddr::V4(ip) => ip,
|
||||
IpAddr::V6(ip) => {
|
||||
if let Some(ip) = ip.to_ipv4_mapped() {
|
||||
ip
|
||||
} else {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
'a: for stun_server in &self.stun_server {
|
||||
for x in stun_server.to_socket_addrs()? {
|
||||
if source_addr.port() == x.port() {
|
||||
if let IpAddr::V4(ip) = x.ip() {
|
||||
if ip == source_ip {
|
||||
check_fail = false;
|
||||
break 'a;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
if check_fail {
|
||||
return Ok(false);
|
||||
}
|
||||
let ip = addr.ip();
|
||||
if !ip.is_multicast()
|
||||
&& !ip.is_broadcast()
|
||||
&& !ip.is_unspecified()
|
||||
&& !ip.is_loopback()
|
||||
&& !ip.is_private()
|
||||
{
|
||||
self.update_addr(index, *addr.ip(), addr.port());
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
|
||||
+44
-6
@@ -4,6 +4,7 @@ use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::channel::punch::NatType;
|
||||
use rand::RngCore;
|
||||
use std::net::UdpSocket;
|
||||
use stun_format::Attr;
|
||||
|
||||
@@ -79,8 +80,7 @@ pub fn stun_test_nat0(stun_servers: Vec<String>) -> io::Result<(NatType, Vec<Ipv
|
||||
|
||||
fn test_nat(udp: &UdpSocket, stun_server: &String) -> io::Result<HashSet<SocketAddr>> {
|
||||
udp.connect(stun_server)?;
|
||||
// 随便搞个当id
|
||||
let tid = stun_server.as_ptr() as u128;
|
||||
let tid = rand::thread_rng().next_u64() as u128;
|
||||
let mut addr = HashSet::new();
|
||||
let (mapped_addr1, changed_addr1) = test_nat_(&udp, true, true, tid)?;
|
||||
if mapped_addr1.is_ipv4() {
|
||||
@@ -119,13 +119,12 @@ fn test_nat_(
|
||||
for _ in 0..2 {
|
||||
let mut buf = [0u8; 28];
|
||||
let mut msg = stun_format::MsgBuilder::from(buf.as_mut_slice());
|
||||
msg.typ(stun_format::MsgType::BindingRequest).unwrap();
|
||||
msg.tid(tid).unwrap();
|
||||
msg.typ(stun_format::MsgType::BindingRequest);
|
||||
msg.tid(tid);
|
||||
msg.add_attr(Attr::ChangeRequest {
|
||||
change_ip,
|
||||
change_port,
|
||||
})
|
||||
.unwrap();
|
||||
});
|
||||
udp.send(msg.as_bytes())?;
|
||||
let mut buf = [0; 10240];
|
||||
let (len, _addr) = match udp.recv_from(&mut buf) {
|
||||
@@ -178,3 +177,42 @@ fn stun_addr(addr: stun_format::SocketAddr) -> SocketAddr {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const TAG: u128 = 1827549368 << 64;
|
||||
|
||||
pub fn send_stun_request() -> Vec<u8> {
|
||||
let mut buf = [0u8; 28];
|
||||
let mut msg = stun_format::MsgBuilder::from(buf.as_mut_slice());
|
||||
msg.typ(stun_format::MsgType::BindingRequest);
|
||||
let id = rand::thread_rng().next_u64() as u128;
|
||||
msg.tid(id | TAG);
|
||||
msg.add_attr(Attr::ChangeRequest {
|
||||
change_ip: false,
|
||||
change_port: false,
|
||||
});
|
||||
msg.as_bytes().to_vec()
|
||||
}
|
||||
|
||||
pub fn recv_stun_response(buf: &[u8]) -> Option<SocketAddr> {
|
||||
if buf[0] != 0x01 && buf[1] != 0x01 {
|
||||
return None;
|
||||
}
|
||||
let msg = stun_format::Msg::from(buf);
|
||||
if let Some(tid) = msg.tid() {
|
||||
if tid & TAG != TAG {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
for x in msg.attrs_iter() {
|
||||
match x {
|
||||
Attr::MappedAddress(addr) => {
|
||||
return Some(stun_addr(addr));
|
||||
}
|
||||
Attr::XorMappedAddress(addr) => {
|
||||
return Some(stun_addr(addr));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user