支持ipv6

This commit is contained in:
lubeilin
2023-09-02 23:57:32 +08:00
parent eec7d73ebe
commit 1a4e375dbf
13 changed files with 199 additions and 77 deletions
+1 -1
View File
@@ -118,7 +118,7 @@ A virtual network tool (VPN)
### Todo
- 桌面UI(测试中)
- 支持Ipv6
- 支持Ipv6(1.2.2已支持客户端之间的ipv6,待支持客户端和服务端之间的ipv6通信)
### 常见问题
<details> <summary>展开</summary>
+2
View File
@@ -62,6 +62,8 @@
| `>=`8 | aes_gcm | AES256-GCM |
| 1~8位 | aes_cbc | AES128-CBC |
| `>=`8 | aes_cbc | AES256-CBC |
### --finger
开启数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启,开启会损耗一部分性能
### --relay
禁用p2p,在网络环境很差时,只使用服务器中转效果可能更好(可以配合--tcp参数一起使用)
+2 -1
View File
@@ -9,7 +9,8 @@ pub struct Info {
pub relay_server: String,
pub nat_type: String,
pub public_ips: String,
pub local_ip: String,
pub local_addr: String,
pub ipv6_addr: String,
}
#[derive(Serialize, Deserialize, Debug)]
+9 -3
View File
@@ -83,7 +83,7 @@ pub fn command_list(vnt: &Vnt) -> Vec<DeviceItem> {
let nat_type = format!("{:?}", nat_info.nat_type);
let public_ips: Vec<String> = nat_info.public_ips.iter().map(|v| v.to_string()).collect();
let public_ips = public_ips.join(",");
let local_ip = nat_info.local_ip.to_string();
let local_ip = nat_info.local_ipv4_addr.ip().to_string();
(nat_type, public_ips, local_ip)
} else {
("".to_string(), "".to_string(), "".to_string())
@@ -136,7 +136,12 @@ pub fn command_info(vnt: &Vnt) -> Info {
let nat_type = format!("{:?}", nat_info.nat_type);
let public_ips: Vec<String> = nat_info.public_ips.iter().map(|v| v.to_string()).collect();
let public_ips = public_ips.join(",");
let local_ip = nat_info.local_ip.to_string();
let local_addr = nat_info.local_ipv4_addr.to_string();
let ipv6_addr = if nat_info.ipv6_addr.ip().is_unspecified() {
"None".to_string()
} else {
nat_info.ipv6_addr.ip().to_string()
};
Info {
name,
virtual_ip,
@@ -146,7 +151,8 @@ pub fn command_info(vnt: &Vnt) -> Info {
relay_server,
nat_type,
public_ips,
local_ip,
local_addr,
ipv6_addr,
}
}
+2 -1
View File
@@ -13,7 +13,8 @@ pub fn console_info(status: Info) {
println!("NAT type: {}", style(status.nat_type).green());
println!("Relay server: {}", style(status.relay_server).green());
println!("Public ips: {}", style(status.public_ips).green());
println!("Local ip: {}", style(status.local_ip).green());
println!("Local addr: {}", style(status.local_addr).green());
println!("IPv6: {}", style(status.ipv6_addr).green());
}
pub fn console_route_table(mut list: Vec<RouteItem>) {
+48 -18
View File
@@ -2,28 +2,32 @@ use std::io;
use std::net::{Ipv4Addr, SocketAddr};
use std::sync::Arc;
use std::time::{Duration, Instant};
use byte_pool::{Block, BytePool};
use crossbeam_utils::atomic::AtomicCell;
use dashmap::DashMap;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpStream, UdpSocket};
use tokio::net::tcp::OwnedReadHalf;
use tokio::sync::watch::{channel, Receiver, Sender};
use crate::channel::{Route, RouteKey, Status};
use crate::channel::punch::NatType;
use crate::core::status::VntWorker;
use crate::handle::CurrentDeviceInfo;
use crate::handle::recv_handler::ChannelDataHandler;
use byte_pool::{Block, BytePool};
lazy_static::lazy_static! {
static ref POOL:BytePool = BytePool::new();
}
pub struct ContextInner {
//udp用于打洞、服务端通信(可选)
pub(crate) main_channel: Arc<UdpSocket>,
pub(crate) main_channel_ipv6: Option<Arc<UdpSocket>>,
//在udp的基础上,可以选择使用tcp和服务端通信
pub(crate) main_tcp_channel: Option<tokio::sync::mpsc::Sender<Vec<u8>>>,
pub(crate) route_table: DashMap<Ipv4Addr, Vec<Route>>,
pub(crate) route_table_time: DashMap<(RouteKey, Ipv4Addr), AtomicCell<Instant>>,
pub(crate) route_table_time: DashMap<(RouteKey, Ipv4Addr), Instant>,
pub(crate) status_receiver: Receiver<Status>,
pub(crate) status_sender: Sender<Status>,
pub(crate) udp_map: DashMap<usize, Arc<UdpSocket>>,
@@ -37,12 +41,13 @@ pub struct Context {
}
impl Context {
pub fn new(main_channel: Arc<UdpSocket>, main_tcp_channel: Option<tokio::sync::mpsc::Sender<Vec<u8>>>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>, _channel_num: usize) -> Self {
pub fn new(main_channel: Arc<UdpSocket>, main_channel_ipv6: Option<Arc<UdpSocket>>, main_tcp_channel: Option<tokio::sync::mpsc::Sender<Vec<u8>>>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>, _channel_num: usize) -> Self {
//当前版本只支持一个通道
let channel_num = 1;
let (status_sender, status_receiver) = channel(Status::Cone);
let inner = Arc::new(ContextInner {
main_channel,
main_channel_ipv6,
main_tcp_channel,
route_table: DashMap::with_capacity(16),
route_table_time: DashMap::with_capacity(16),
@@ -87,11 +92,37 @@ impl Context {
pub fn switch_to_symmetric(&self) {
let _ = self.inner.status_sender.send(Status::Symmetric);
}
pub fn main_local_port(&self) -> io::Result<u16> {
pub fn main_local_ipv4_port(&self) -> io::Result<u16> {
self.inner.main_channel.local_addr().map(|k| k.port())
}
pub fn main_local_ipv6_port(&self) -> io::Result<u16> {
if let Some(ipv6) = &self.inner.main_channel_ipv6{
ipv6.local_addr().map(|k| k.port())
}else{
Err(io::Error::new(io::ErrorKind::Other, "not ipv6"))
}
}
pub async fn send_main_udp(&self, buf: &[u8], addr: SocketAddr) -> io::Result<usize> {
self.inner.main_channel.send_to(buf, addr).await
if addr.is_ipv6() {
if let Some(udp_ipv6) = &self.inner.main_channel_ipv6 {
udp_ipv6.send_to(buf, addr).await
} else {
Err(io::Error::new(io::ErrorKind::Other, "not ipv6"))
}
} else {
self.inner.main_channel.send_to(buf, addr).await
}
}
pub fn try_send_main_udp(&self, buf: &[u8], addr: SocketAddr) -> io::Result<usize> {
if addr.is_ipv6() {
if let Some(udp_ipv6) = &self.inner.main_channel_ipv6 {
udp_ipv6.try_send_to(buf, addr)
} else {
Err(io::Error::new(io::ErrorKind::Other, "not ipv6"))
}
} else {
self.inner.main_channel.try_send_to(buf, addr)
}
}
pub async fn send_main(&self, buf: &[u8], addr: SocketAddr) -> io::Result<usize> {
if let Some(sender) = &self.inner.main_tcp_channel {
@@ -101,7 +132,7 @@ impl Context {
Err(io::Error::new(io::ErrorKind::Other, "send_main err"))
}
} else {
self.inner.main_channel.send_to(buf, addr).await
self.send_main_udp(buf, addr).await
}
}
pub fn try_send_main(&self, buf: &[u8], addr: SocketAddr) -> io::Result<usize> {
@@ -112,7 +143,7 @@ impl Context {
Err(io::Error::new(io::ErrorKind::Other, "try_send_main err"))
}
} else {
self.inner.main_channel.try_send_to(buf, addr)
self.try_send_main_udp(buf, addr)
}
}
@@ -120,7 +151,8 @@ impl Context {
for udp_ref in self.inner.udp_map.iter() {
let udp = udp_ref.clone();
drop(udp_ref);
udp.send_to(buf, addr).await?;
//使用ipv6的udp发送ipv4报文会出错
let _ = udp.send_to(buf, addr).await;
}
Ok(())
}
@@ -135,17 +167,12 @@ impl Context {
if !route.is_p2p() {
if let Some(time) = self.inner.route_table_time.get(&(route.route_key(), *id)) {
//借道传输时,长时间不通信的通道不使用
if time.value().load().elapsed() > Duration::from_secs(6) {
if time.value().elapsed() > Duration::from_secs(6) {
return Err(io::Error::new(io::ErrorKind::NotFound, "route time out"));
}
}
}
if let Some(udp_ref) = self.inner.udp_map.get(&route.index) {
let udp = udp_ref.value().clone();
drop(udp_ref);
return udp.send_to(buf, route.addr).await;
}
return self.send_by_key(buf,&route.route_key()).await;
}
Err(io::Error::new(io::ErrorKind::NotFound, "route not found"))
}
@@ -238,7 +265,7 @@ impl Context {
list.truncate(max_len);
}
}
self.inner.route_table_time.insert((key, id), AtomicCell::new(Instant::now()));
self.inner.route_table_time.insert((key, id), Instant::now());
}
pub fn route(&self, id: &Ipv4Addr) -> Option<Vec<Route>> {
if let Some(v) = self.inner.route_table.get(id) {
@@ -312,8 +339,8 @@ impl Context {
self.inner.route_table_time.remove(&(route_key, *id));
}
pub fn update_read_time(&self, id: &Ipv4Addr, route_key: &RouteKey) {
if let Some(time) = self.inner.route_table_time.get(&(*route_key, *id)) {
time.value().store(Instant::now());
if let Some(mut time) = self.inner.route_table_time.get_mut(&(*route_key, *id)) {
*time.value_mut() = Instant::now();
}
}
}
@@ -465,6 +492,9 @@ impl Channel {
if let Some((tcp_stream, receiver)) = tcp {
tokio::spawn(Self::start_tcp(worker.worker("main_channel_tcp"), tcp_stream, receiver, context.inner.current_device.clone(), buf_sender.clone().unwrap(), head_reserve));
}
if let Some(main_channel_ipv6) = &context.inner.main_channel_ipv6 {
tokio::spawn(Self::start_(worker.worker("main_channel_ipv6"), context.clone(), main_channel_ipv6.clone(), handler.clone(), buf_sender.clone(), head_reserve, true));
}
tokio::spawn(Self::start_(worker.worker("main_channel_1"), context.clone(), main_channel.clone(), handler.clone(), buf_sender.clone(), head_reserve, true));
if relay {
worker.stop_wait().await;
+1 -1
View File
@@ -27,7 +27,7 @@ impl Idle {
loop {
let mut max = Duration::from_secs(0);
for entry in self.context.inner.route_table_time.iter() {
let last_read = entry.value().load().elapsed();
let last_read = entry.value().elapsed();
if last_read >= self.read_idle {
return Ok((entry.key().1.clone(), entry.key().0.clone()));
} else {
+12 -9
View File
@@ -1,6 +1,6 @@
use std::collections::HashMap;
use std::io;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::time::Duration;
use rand::prelude::SliceRandom;
@@ -12,8 +12,8 @@ pub struct NatInfo {
pub public_ips: Vec<Ipv4Addr>,
pub public_port: u16,
pub public_port_range: u16,
pub local_ip: Ipv4Addr,
pub local_port: u16,
pub local_ipv4_addr: SocketAddrV4,
pub ipv6_addr: SocketAddrV6,
pub nat_type: NatType,
}
@@ -27,8 +27,8 @@ impl NatInfo {
pub fn new(mut public_ips: Vec<Ipv4Addr>,
public_port: u16,
public_port_range: u16,
local_ip: Ipv4Addr,
local_port: u16,
local_ipv4_addr: SocketAddrV4,
ipv6_addr: SocketAddrV6,
nat_type: NatType, ) -> Self {
public_ips.retain(|ip| {
!ip.is_loopback() && !ip.is_private()
@@ -37,8 +37,8 @@ impl NatInfo {
public_ips,
public_port,
public_port_range,
local_ip,
local_port,
local_ipv4_addr,
ipv6_addr,
nat_type,
}
}
@@ -70,8 +70,11 @@ impl Punch {
if !self.context.need_punch(&id) {
return Ok(());
}
if !nat_info.local_ip.is_unspecified() || nat_info.local_port != 0 {
let _ = self.context.send_main_udp(buf, SocketAddr::V4(SocketAddrV4::new(nat_info.local_ip, nat_info.local_port))).await;
if !nat_info.local_ipv4_addr.ip().is_unspecified() && nat_info.local_ipv4_addr.port() != 0 {
let _ = self.context.send_main_udp(buf, SocketAddr::V4(nat_info.local_ipv4_addr)).await;
}
if !nat_info.ipv6_addr.ip().is_unspecified() && nat_info.ipv6_addr.port() != 0 {
let _ = self.context.send_main_udp(buf, SocketAddr::V6(nat_info.ipv6_addr)).await;
}
match nat_info.nat_type {
NatType::Symmetric => {
+22 -6
View File
@@ -54,6 +54,7 @@ pub struct Vnt {
pub struct VntUtil {
config: Config,
main_channel: UdpSocket,
main_channel_ipv6: Option<UdpSocket>,
main_tcp_channel: Option<TcpStream>,
response: Option<RegResponse>,
iface: Option<(DeviceWriter, DeviceReader)>,
@@ -64,6 +65,15 @@ pub struct VntUtil {
impl VntUtil {
pub async fn new(config: Config) -> io::Result<VntUtil> {
let main_channel = UdpSocket::bind("0.0.0.0:0").await?;
let main_channel_ipv6 = match UdpSocket::bind("[::]:0").await {
Ok(main_channel_ipv6) => {
Some(main_channel_ipv6)
}
Err(e) => {
log::warn!("绑定ipv6地址失败:{}",e);
None
}
};
let server_cipher = if config.server_encrypt {
let mut key = [0 as u8; 32];
rand::thread_rng().fill(&mut key);
@@ -74,6 +84,7 @@ impl VntUtil {
Ok(VntUtil {
config,
main_channel,
main_channel_ipv6,
main_tcp_channel: None,
response: None,
iface: None,
@@ -150,9 +161,9 @@ impl VntUtil {
let mtu = match self.config.mtu {
None => {
if self.config.password.is_none() {
1430
1450
} else {
1410
1420
}
}
Some(mtu) => {
@@ -204,7 +215,9 @@ impl VntUtil {
} else {
(None, None)
};
let context = Context::new(Arc::new(self.main_channel), tcp_sender, current_device.clone(), 1);
let context = Context::new(Arc::new(self.main_channel),
self.main_channel_ipv6.map(|v| Arc::new(v)),
tcp_sender, current_device.clone(), 1);
let punch = Punch::new(context.clone());
let idle = Idle::new(Duration::from_secs(16), context.clone());
let channel_sender = ChannelSender::new(context.clone());
@@ -216,11 +229,14 @@ impl VntUtil {
let peer_nat_info_map: Arc<DashMap<Ipv4Addr, NatInfo>> = Arc::new(DashMap::new());
let connect_status = Arc::new(AtomicCell::new(ConnectStatus::Connected));
let local_port = context.main_local_ipv4_port().unwrap_or(0);
let local_ip = crate::nat::local_ip()?;
let local_port = context.main_local_port()?;
let local_ipv4_addr = crate::nat::local_ipv4_addr(local_port);
let ipv6_port = context.main_local_ipv6_port().unwrap_or(0);
let ipv6_addr = crate::nat::local_ipv6_addr(ipv6_port);
// NAT检测
let nat_test = NatTest::new(config.stun_server.clone(), response.public_ip, response.public_port, local_ip, local_port).await;
let nat_test = NatTest::new(config.stun_server.clone(), response.public_ip,
response.public_port, local_ipv4_addr, ipv6_addr).await;
let in_external_route = if config.in_ips.is_empty() {
None
} else {
+3
View File
@@ -35,6 +35,7 @@ pub fn start_idle(mut worker: VntWorker, idle: Idle, sender: ChannelSender) {
}
async fn start_idle_(idle: Idle, sender: ChannelSender) -> io::Result<()> {
log::info!("启动空闲检查任务");
loop {
let (peer_ip, route) = idle.next_idle().await?;
log::info!(
@@ -103,6 +104,7 @@ async fn start_heartbeat_(
server_cipher: Cipher,
) -> io::Result<()> {
let mut count = 0;
log::info!("启动心跳任务");
loop {
if sender.is_close() {
return Ok(());
@@ -129,6 +131,7 @@ async fn start_heartbeat_(
if addr != current_dev.connect_server {
let mut tmp = current_dev.clone();
tmp.connect_server = addr;
log::info!("服务端地址变化,旧地址:{},新地址:{}",current_dev.connect_server,addr);
if current_device.compare_exchange(current_dev, tmp).is_ok() {
current_dev.connect_server = addr;
}
+8 -2
View File
@@ -34,6 +34,7 @@ pub fn start(mut worker: VntWorker, receiver: Receiver<(Ipv4Addr, NatInfo)>,
pub async fn start0(mut receiver: Receiver<(Ipv4Addr, NatInfo)>,
mut punch: Punch, current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher, ) {
log::info!("启动打洞任务");
while let Some((peer_ip, nat_info)) = receiver.recv().await {
if let Err(e) = start_(&client_cipher, &mut punch, &current_device, peer_ip, nat_info).await {
log::warn!("网络打洞异常 {:?}", e);
@@ -70,6 +71,7 @@ pub async fn start_punch(
) {
let mut num = 0;
let sleep_time = [3, 5, 7, 11, 13, 17, 19, 23, 29];
log::info!("启动发起打洞请求任务");
loop {
if sender.is_close() {
break;
@@ -135,8 +137,12 @@ pub fn punch_packet(
.collect();
punch_reply.public_port = nat_info.public_port as u32;
punch_reply.public_port_range = nat_info.public_port_range as u32;
punch_reply.local_ip = u32::from_be_bytes(nat_info.local_ip.octets());
punch_reply.local_port = nat_info.local_port as u32;
punch_reply.local_ip = u32::from_be_bytes(nat_info.local_ipv4_addr.ip().octets());
punch_reply.local_port = nat_info.local_ipv4_addr.port() as u32;
if !nat_info.ipv6_addr.ip().is_unspecified() {
punch_reply.ipv6_port = nat_info.ipv6_addr.port() as u32;
punch_reply.ipv6 = nat_info.ipv6_addr.ip().octets().to_vec();
}
punch_reply.nat_type = protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
let bytes = punch_reply.write_to_bytes()?;
let mut net_packet = NetPacket::new_encrypt(vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED])?;
+35 -19
View File
@@ -1,4 +1,4 @@
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
use std::sync::Arc;
use crossbeam_utils::atomic::AtomicCell;
@@ -370,11 +370,19 @@ impl ChannelDataHandler {
let punch_info = PunchInfo::parse_from_bytes(net_packet.payload())?;
let public_ips = punch_info.public_ip_list.
iter().map(|v| { Ipv4Addr::from(v.to_be_bytes()) }).collect();
let local_ipv4_addr = SocketAddrV4::new(Ipv4Addr::from(punch_info.local_ip.to_be_bytes()), punch_info.local_port as u16);
let ipv6_addr = if punch_info.ipv6.len() == 16 {
let ipv6: [u8; 16] = punch_info.ipv6.try_into().unwrap();
SocketAddrV6::new(Ipv6Addr::from(ipv6), punch_info.ipv6_port as u16, 0, 0)
} else {
SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0)
};
let peer_nat_info = NatInfo::new(public_ips,
punch_info.public_port as u16,
punch_info.public_port_range as u16,
Ipv4Addr::from(punch_info.local_ip.to_be_bytes()),
punch_info.local_port as u16,
local_ipv4_addr,
ipv6_addr,
punch_info.nat_type.enum_value_or_default().into());
self.peer_nat_info_map.insert(source, peer_nat_info.clone());
if !punch_info.reply {
@@ -386,8 +394,12 @@ impl ChannelDataHandler {
punch_reply.public_port_range = nat_info.public_port_range as u32;
punch_reply.nat_type =
protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
punch_reply.local_ip = u32::from_be_bytes(nat_info.local_ip.octets());
punch_reply.local_port = nat_info.local_port as u32;
punch_reply.local_ip = u32::from_be_bytes(nat_info.local_ipv4_addr.ip().octets());
punch_reply.local_port = nat_info.local_ipv4_addr.port() as u32;
if !nat_info.ipv6_addr.ip().is_unspecified() {
punch_reply.ipv6 = nat_info.ipv6_addr.ip().octets().to_vec();
punch_reply.ipv6_port = nat_info.ipv6_addr.port() as u32;
}
let bytes = punch_reply.write_to_bytes()?;
let mut punch_packet =
NetPacket::new_encrypt(vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED])?;
@@ -400,17 +412,18 @@ impl ChannelDataHandler {
punch_packet.set_source(current_device.virtual_ip());
punch_packet.set_destination(source);
punch_packet.set_payload(&bytes)?;
if !peer_nat_info.local_ip.is_unspecified() && peer_nat_info.local_port != 0 {
let mut packet = NetPacket::new_encrypt([0u8; 12 + ENCRYPTION_RESERVED])?;
packet.set_version(Version::V1);
packet.first_set_ttl(1);
packet.set_protocol(Protocol::Control);
packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
packet.set_source(current_device.virtual_ip());
packet.set_destination(source);
self.client_cipher.encrypt_ipv4(&mut packet)?;
let _ = context.send_main(packet.buffer(), SocketAddr::V4(SocketAddrV4::new(peer_nat_info.local_ip, peer_nat_info.local_port))).await;
}
// if !peer_nat_info.local_ip.is_unspecified() && peer_nat_info.local_port != 0 {
// let mut packet = NetPacket::new_encrypt([0u8; 12 + ENCRYPTION_RESERVED])?;
// packet.set_version(Version::V1);
// packet.first_set_ttl(1);
// packet.set_protocol(Protocol::Control);
// packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
// packet.set_source(current_device.virtual_ip());
// packet.set_destination(source);
// self.client_cipher.encrypt_ipv4(&mut packet)?;
// let _ = context.try_send_main_udp(packet.buffer(),
// SocketAddr::V4(SocketAddrV4::new(peer_nat_info.local_ip, peer_nat_info.local_port)));
// }
if self.punch(source, peer_nat_info).await {
self.client_cipher.encrypt_ipv4(&mut punch_packet)?;
context.send_by_key(punch_packet.buffer(), route_key).await?;
@@ -512,10 +525,13 @@ impl ChannelDataHandler {
service_packet::Protocol::RegistrationRequest => {}
service_packet::Protocol::RegistrationResponse => {
let response = RegistrationResponse::parse_from_bytes(net_packet.payload())?;
let local_port = context.main_local_port()?;
let local_ip = nat::local_ip()?;
let local_port = context.main_local_ipv4_port().unwrap_or(0);
let local_ipv4_addr = nat::local_ipv4_addr(local_port);
let local_port = context.main_local_ipv6_port().unwrap_or(0);
let ipv6_addr = nat::local_ipv6_addr(local_port);
let nat_info = self.nat_test.re_test(Ipv4Addr::from(response.public_ip),
response.public_port as u16, local_ip, local_port).await;
response.public_port as u16,
local_ipv4_addr, ipv6_addr).await;
context.switch(nat_info.nat_type);
let new_ip = Ipv4Addr::from(response.virtual_ip);
let current_ip = current_device.virtual_ip();
+54 -16
View File
@@ -1,5 +1,5 @@
use std::io;
use std::net::{IpAddr, Ipv4Addr};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
use std::net::UdpSocket;
use std::sync::Arc;
@@ -10,7 +10,7 @@ use crate::proto::message::PunchNatType;
mod stun_test;
pub fn local_ip() -> io::Result<Ipv4Addr> {
pub fn local_ipv4() -> io::Result<Ipv4Addr> {
let socket = UdpSocket::bind("0.0.0.0:0")?;
socket.connect("8.8.8.8:80")?;
let addr = socket.local_addr()?;
@@ -24,6 +24,44 @@ pub fn local_ip() -> io::Result<Ipv4Addr> {
}
}
pub fn local_ipv6() -> io::Result<Ipv6Addr> {
let socket = UdpSocket::bind("[::]:0")?;
socket.connect("[2001:4860:4860::8888]:80")?;
let addr = socket.local_addr()?;
match addr.ip() {
IpAddr::V4(_) => {
Ok(Ipv6Addr::UNSPECIFIED)
}
IpAddr::V6(ip) => {
Ok(ip)
}
}
}
pub fn local_ipv4_addr(port: u16) -> SocketAddrV4 {
match local_ipv4() {
Ok(ipv4) => {
SocketAddrV4::new(ipv4, port)
}
Err(e) => {
log::warn!("获取本地ipv4地址失败:{}",e);
SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0)
}
}
}
pub fn local_ipv6_addr(port: u16) -> SocketAddrV6 {
match local_ipv6() {
Ok(ipv6) => {
SocketAddrV6::new(ipv6, port, 0, 0)
}
Err(e) => {
log::warn!("获取本地ipv6地址失败:{}",e);
SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0)
}
}
}
#[derive(Clone)]
pub struct NatTest {
stun_server: Vec<String>,
@@ -53,8 +91,8 @@ impl NatTest {
mut stun_server: Vec<String>,
public_ip: Ipv4Addr,
public_port: u16,
local_ip: Ipv4Addr,
local_port: u16,
local_ipv4_addr: SocketAddrV4,
ipv6_addr: SocketAddrV6,
) -> NatTest {
let server = stun_server[0].clone();
stun_server.resize(3, server);
@@ -62,8 +100,8 @@ impl NatTest {
&stun_server,
public_ip,
public_port,
local_ip,
local_port,
local_ipv4_addr,
ipv6_addr,
).await;
NatTest {
stun_server,
@@ -84,15 +122,15 @@ impl NatTest {
&self,
public_ip: Ipv4Addr,
public_port: u16,
local_ip: Ipv4Addr,
local_port: u16,
local_ipv4_addr: SocketAddrV4,
ipv6_addr: SocketAddrV6,
) -> NatInfo {
let info = NatTest::re_test_(
&self.stun_server,
public_ip,
public_port,
local_ip,
local_port,
local_ipv4_addr,
ipv6_addr,
).await;
*self.info.lock() = info.clone();
info
@@ -101,8 +139,8 @@ impl NatTest {
stun_server: &Vec<String>,
public_ip: Ipv4Addr,
public_port: u16,
local_ip: Ipv4Addr,
local_port: u16,
local_ipv4_addr: SocketAddrV4,
ipv6_addr: SocketAddrV6,
) -> NatInfo {
return match stun_test::stun_test_nat(stun_server.clone()).await {
Ok((nat_type, ips, port_range)) => {
@@ -117,8 +155,8 @@ impl NatTest {
public_ips,
public_port,
port_range,
local_ip,
local_port,
local_ipv4_addr,
ipv6_addr,
nat_type,
)
}
@@ -128,8 +166,8 @@ impl NatTest {
vec![public_ip],
public_port,
0,
local_ip,
local_port,
local_ipv4_addr,
ipv6_addr,
NatType::Cone,
)
}