修改stun
This commit is contained in:
+4
-4
@@ -156,9 +156,9 @@ pub fn parse_args_config() -> anyhow::Result<Option<(Config, Vec<String>, bool)>
|
|||||||
|
|
||||||
let mut stun_server = matches.opt_strs("e");
|
let mut stun_server = matches.opt_strs("e");
|
||||||
if stun_server.is_empty() {
|
if stun_server.is_empty() {
|
||||||
stun_server.push("stun1.l.google.com:19302".to_string());
|
for x in config::PUB_STUN {
|
||||||
stun_server.push("stun2.l.google.com:19302".to_string());
|
stun_server.push(x.to_string());
|
||||||
stun_server.push("stun.miwifi.com:3478".to_string());
|
}
|
||||||
}
|
}
|
||||||
let dns = matches.opt_strs("dns");
|
let dns = matches.opt_strs("dns");
|
||||||
let in_ip = matches.opt_strs("i");
|
let in_ip = matches.opt_strs("i");
|
||||||
@@ -340,7 +340,7 @@ fn print_usage(program: &str, _opts: Options) {
|
|||||||
println!(" -n <name> 给设备一个名字,便于区分不同设备,默认使用系统版本");
|
println!(" -n <name> 给设备一个名字,便于区分不同设备,默认使用系统版本");
|
||||||
println!(" -d <id> 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复");
|
println!(" -d <id> 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复");
|
||||||
println!(" -s <server> 注册和中继服务器地址,以'TXT:'开头表示解析TXT记录");
|
println!(" -s <server> 注册和中继服务器地址,以'TXT:'开头表示解析TXT记录");
|
||||||
println!(" -e <stun-server> stun服务器,用于探测NAT类型,可使用多个地址,如-e stun1.l.google.com -e stun2.l.google.com");
|
println!(" -e <stun-server> stun服务器,用于探测NAT类型,可使用多个地址,如-e stun.miwifi.com -e turn.cloudflare.com");
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
#[cfg(feature = "integrated_tun")]
|
#[cfg(feature = "integrated_tun")]
|
||||||
println!(
|
println!(
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ use anyhow::anyhow;
|
|||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::args_parse;
|
|
||||||
use crate::config::get_device_id;
|
use crate::config::get_device_id;
|
||||||
|
use crate::{args_parse, config};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use vnt::channel::punch::PunchModel;
|
use vnt::channel::punch::PunchModel;
|
||||||
use vnt::channel::UseChannelType;
|
use vnt::channel::UseChannelType;
|
||||||
@@ -49,6 +49,10 @@ pub struct FileConfig {
|
|||||||
|
|
||||||
impl Default for FileConfig {
|
impl Default for FileConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
let mut stun_server = Vec::new();
|
||||||
|
for x in config::PUB_STUN {
|
||||||
|
stun_server.push(x.to_string());
|
||||||
|
}
|
||||||
Self {
|
Self {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
tap: false,
|
tap: false,
|
||||||
@@ -59,11 +63,7 @@ impl Default for FileConfig {
|
|||||||
.unwrap_or("UnknownName")
|
.unwrap_or("UnknownName")
|
||||||
.to_string(),
|
.to_string(),
|
||||||
server_address: "nat1.wherewego.top:29872".to_string(),
|
server_address: "nat1.wherewego.top:29872".to_string(),
|
||||||
stun_server: vec![
|
stun_server,
|
||||||
"stun1.l.google.com:19302".to_string(),
|
|
||||||
"stun2.l.google.com:19302".to_string(),
|
|
||||||
"stun.miwifi.com:3478".to_string(),
|
|
||||||
],
|
|
||||||
dns: vec![],
|
dns: vec![],
|
||||||
in_ips: vec![],
|
in_ips: vec![],
|
||||||
out_ips: vec![],
|
out_ips: vec![],
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
pub const PUB_STUN: [&'static str; 4] = [
|
||||||
|
"stun.miwifi.com",
|
||||||
|
"stun.chat.bilibili.com",
|
||||||
|
"stun.hitv.com",
|
||||||
|
"stun.cdnbye.com",
|
||||||
|
];
|
||||||
#[cfg(feature = "file_config")]
|
#[cfg(feature = "file_config")]
|
||||||
mod file_config;
|
mod file_config;
|
||||||
|
|
||||||
|
|||||||
+54
-9
@@ -8,6 +8,7 @@ use std::time::{Duration, Instant};
|
|||||||
|
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
use rand::prelude::SliceRandom;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use crate::channel::punch::{NatInfo, NatType};
|
use crate::channel::punch::{NatInfo, NatType};
|
||||||
@@ -47,12 +48,60 @@ pub fn local_ipv6_() -> io::Result<Ipv6Addr> {
|
|||||||
|
|
||||||
pub fn local_ipv6() -> Option<Ipv6Addr> {
|
pub fn local_ipv6() -> Option<Ipv6Addr> {
|
||||||
match local_ipv6_() {
|
match local_ipv6_() {
|
||||||
Ok(ipv6) => Some(ipv6),
|
Ok(ipv6) => {
|
||||||
|
if is_ipv6_global(&ipv6) {
|
||||||
|
return Some(ipv6);
|
||||||
|
}
|
||||||
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("获取ipv6失败:{:?}", e);
|
log::warn!("获取ipv6失败:{:?}", e);
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
pub const fn is_ipv4_global(ipv4: &Ipv4Addr) -> bool {
|
||||||
|
!(ipv4.octets()[0] == 0 // "This network"
|
||||||
|
|| ipv4.is_private()
|
||||||
|
|| ipv4.octets()[0] == 100 && (ipv4.octets()[1] & 0b1100_0000 == 0b0100_0000)//ipv4.is_shared()
|
||||||
|
|| ipv4.is_loopback()
|
||||||
|
|| ipv4.is_link_local()
|
||||||
|
// addresses reserved for future protocols (`192.0.0.0/24`)
|
||||||
|
// .9 and .10 are documented as globally reachable so they're excluded
|
||||||
|
|| (
|
||||||
|
ipv4.octets()[0] == 192 && ipv4.octets()[1] == 0 && ipv4.octets()[2] == 0
|
||||||
|
&& ipv4.octets()[3] != 9 && ipv4.octets()[3] != 10
|
||||||
|
)
|
||||||
|
|| ipv4.is_documentation()
|
||||||
|
|| ipv4.octets()[0] == 198 && (ipv4.octets()[1] & 0xfe) == 18//ipv4.is_benchmarking()
|
||||||
|
|| ipv4.octets()[0] & 240 == 240 && !ipv4.is_broadcast()//ipv4.is_reserved()
|
||||||
|
|| ipv4.is_broadcast())
|
||||||
|
}
|
||||||
|
pub const fn is_ipv6_global(ipv6addr: &Ipv6Addr) -> bool {
|
||||||
|
!(ipv6addr.is_unspecified()
|
||||||
|
|| ipv6addr.is_loopback()
|
||||||
|
// IPv4-mapped Address (`::ffff:0:0/96`)
|
||||||
|
|| matches!(ipv6addr.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
|
||||||
|
// IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
|
||||||
|
|| matches!(ipv6addr.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
|
||||||
|
// Discard-Only Address Block (`100::/64`)
|
||||||
|
|| matches!(ipv6addr.segments(), [0x100, 0, 0, 0, _, _, _, _])
|
||||||
|
// IETF Protocol Assignments (`2001::/23`)
|
||||||
|
|| (matches!(ipv6addr.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
|
||||||
|
&& !(
|
||||||
|
// Port Control Protocol Anycast (`2001:1::1`)
|
||||||
|
u128::from_be_bytes(ipv6addr.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
|
||||||
|
// Traversal Using Relays around NAT Anycast (`2001:1::2`)
|
||||||
|
|| u128::from_be_bytes(ipv6addr.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
|
||||||
|
// AMT (`2001:3::/32`)
|
||||||
|
|| matches!(ipv6addr.segments(), [0x2001, 3, _, _, _, _, _, _])
|
||||||
|
// AS112-v6 (`2001:4:112::/48`)
|
||||||
|
|| matches!(ipv6addr.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
|
||||||
|
// ORCHIDv2 (`2001:20::/28`)
|
||||||
|
|| matches!(ipv6addr.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
|
||||||
|
))
|
||||||
|
|| (ipv6addr.segments()[0] == 0x2001) && (ipv6addr.segments()[1] == 0xdb8)//ipv6addr.is_documentation()
|
||||||
|
|| (ipv6addr.segments()[0] & 0xfe00) == 0xfc00//ipv6addr.is_unique_local()
|
||||||
|
|| (ipv6addr.segments()[0] & 0xffc0) == 0xfe80) //ipv6addr.is_unicast_link_local())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -92,7 +141,9 @@ impl NatTest {
|
|||||||
tcp_port: u16,
|
tcp_port: u16,
|
||||||
) -> NatTest {
|
) -> NatTest {
|
||||||
if stun_server.len() > 5 {
|
if stun_server.len() > 5 {
|
||||||
|
stun_server.shuffle(&mut rand::thread_rng());
|
||||||
stun_server.truncate(5);
|
stun_server.truncate(5);
|
||||||
|
log::info!("stun_server truncate {:?}", stun_server);
|
||||||
}
|
}
|
||||||
let ports = vec![0; udp_ports.len()];
|
let ports = vec![0; udp_ports.len()];
|
||||||
let nat_info = NatInfo::new(
|
let nat_info = NatInfo::new(
|
||||||
@@ -266,13 +317,7 @@ impl NatTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !check_fail {
|
if !check_fail {
|
||||||
let ip = addr.ip();
|
if is_ipv4_global(addr.ip()) {
|
||||||
if !ip.is_multicast()
|
|
||||||
&& !ip.is_broadcast()
|
|
||||||
&& !ip.is_unspecified()
|
|
||||||
&& !ip.is_loopback()
|
|
||||||
&& !ip.is_private()
|
|
||||||
{
|
|
||||||
if self.update_addr(index, *addr.ip(), addr.port()) {
|
if self.update_addr(index, *addr.ip(), addr.port()) {
|
||||||
log::info!("回应地址{:?},来源stun {:?}", addr, source_addr)
|
log::info!("回应地址{:?},来源stun {:?}", addr, source_addr)
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-11
@@ -9,17 +9,12 @@ use std::net::UdpSocket;
|
|||||||
use stun_format::Attr;
|
use stun_format::Attr;
|
||||||
|
|
||||||
pub fn stun_test_nat(stun_servers: Vec<String>) -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
|
pub fn stun_test_nat(stun_servers: Vec<String>) -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
|
||||||
let mut th = Vec::new();
|
|
||||||
for _ in 0..2 {
|
|
||||||
let stun_servers = stun_servers.clone();
|
|
||||||
let handle = std::thread::spawn(move || stun_test_nat0(stun_servers));
|
|
||||||
th.push(handle);
|
|
||||||
}
|
|
||||||
let mut nat_type = NatType::Cone;
|
let mut nat_type = NatType::Cone;
|
||||||
let mut port_range = 0;
|
let mut port_range = 0;
|
||||||
let mut hash_set = HashSet::new();
|
let mut hash_set = HashSet::new();
|
||||||
for x in th {
|
for _ in 0..2 {
|
||||||
match x.join().unwrap() {
|
let stun_servers = stun_servers.clone();
|
||||||
|
match stun_test_nat0(stun_servers) {
|
||||||
Ok((nat_type_t, ip_list_t, port_range_t)) => {
|
Ok((nat_type_t, ip_list_t, port_range_t)) => {
|
||||||
if nat_type_t == NatType::Symmetric {
|
if nat_type_t == NatType::Symmetric {
|
||||||
nat_type = NatType::Symmetric;
|
nat_type = NatType::Symmetric;
|
||||||
@@ -86,13 +81,13 @@ fn test_nat(udp: &UdpSocket, stun_server: &String) -> io::Result<HashSet<SocketA
|
|||||||
udp.connect(stun_server)?;
|
udp.connect(stun_server)?;
|
||||||
let tid = rand::thread_rng().next_u64() as u128;
|
let tid = rand::thread_rng().next_u64() as u128;
|
||||||
let mut addr = HashSet::new();
|
let mut addr = HashSet::new();
|
||||||
let (mapped_addr1, changed_addr1) = test_nat_(&udp, true, true, tid)?;
|
let (mapped_addr1, changed_addr1) = test_nat_(&udp, stun_server, true, true, tid)?;
|
||||||
if mapped_addr1.is_ipv4() {
|
if mapped_addr1.is_ipv4() {
|
||||||
addr.insert(mapped_addr1);
|
addr.insert(mapped_addr1);
|
||||||
}
|
}
|
||||||
if let Some(changed_addr1) = changed_addr1 {
|
if let Some(changed_addr1) = changed_addr1 {
|
||||||
if udp.connect(changed_addr1).is_ok() {
|
if udp.connect(changed_addr1).is_ok() {
|
||||||
match test_nat_(&udp, false, false, tid + 1) {
|
match test_nat_(&udp, stun_server, false, false, tid + 1) {
|
||||||
Ok((mapped_addr2, _)) => {
|
Ok((mapped_addr2, _)) => {
|
||||||
if mapped_addr2.is_ipv4() {
|
if mapped_addr2.is_ipv4() {
|
||||||
addr.insert(mapped_addr1);
|
addr.insert(mapped_addr1);
|
||||||
@@ -116,6 +111,7 @@ fn test_nat(udp: &UdpSocket, stun_server: &String) -> io::Result<HashSet<SocketA
|
|||||||
|
|
||||||
fn test_nat_(
|
fn test_nat_(
|
||||||
udp: &UdpSocket,
|
udp: &UdpSocket,
|
||||||
|
stun_server: &String,
|
||||||
change_ip: bool,
|
change_ip: bool,
|
||||||
change_port: bool,
|
change_port: bool,
|
||||||
tid: u128,
|
tid: u128,
|
||||||
@@ -134,7 +130,7 @@ fn test_nat_(
|
|||||||
let (len, _addr) = match udp.recv_from(&mut buf) {
|
let (len, _addr) = match udp.recv_from(&mut buf) {
|
||||||
Ok(rs) => rs,
|
Ok(rs) => rs,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("stun error {:?}", e);
|
log::warn!("stun {} error {:?}", stun_server, e);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user