通过stun探测端口,解决使用ipv6或tcp服务时端口错误的问题

This commit is contained in:
lbl8603
2024-05-10 23:18:24 +08:00
parent 699262d79e
commit 3b1236cfd0
6 changed files with 181 additions and 22 deletions
+4
View File
@@ -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
}
}
+53 -13
View File
@@ -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, &current_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,
&current_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(())
}
+1 -1
View File
@@ -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::*;
+14 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
}