ipv6 detection
This commit is contained in:
parent
3009aa66ce
commit
855b7eaf7d
@ -104,7 +104,7 @@ struct NetworkInner {
|
|||||||
public_dial_info_check_punishment: Option<Box<dyn FnOnce() + Send + 'static>>,
|
public_dial_info_check_punishment: Option<Box<dyn FnOnce() + Send + 'static>>,
|
||||||
/// udp socket record for bound-first sockets, which are used to guarantee a port is available before
|
/// udp socket record for bound-first sockets, which are used to guarantee a port is available before
|
||||||
/// creating a 'reuseport' socket there. we don't want to pick ports that other programs are using
|
/// creating a 'reuseport' socket there. we don't want to pick ports that other programs are using
|
||||||
bound_first_udp: BTreeMap<u16, Option<(socket2::Socket, socket2::Socket)>>,
|
bound_first_udp: BTreeMap<u16, (Option<socket2::Socket>, Option<socket2::Socket>)>,
|
||||||
/// mapping of protocol handlers to accept messages from a set of bound socket addresses
|
/// mapping of protocol handlers to accept messages from a set of bound socket addresses
|
||||||
inbound_udp_protocol_handlers: BTreeMap<SocketAddr, RawUdpProtocolHandler>,
|
inbound_udp_protocol_handlers: BTreeMap<SocketAddr, RawUdpProtocolHandler>,
|
||||||
/// outbound udp protocol handler for udpv4
|
/// outbound udp protocol handler for udpv4
|
||||||
@ -113,7 +113,7 @@ struct NetworkInner {
|
|||||||
outbound_udpv6_protocol_handler: Option<RawUdpProtocolHandler>,
|
outbound_udpv6_protocol_handler: Option<RawUdpProtocolHandler>,
|
||||||
/// tcp socket record for bound-first sockets, which are used to guarantee a port is available before
|
/// tcp socket record for bound-first sockets, which are used to guarantee a port is available before
|
||||||
/// creating a 'reuseport' socket there. we don't want to pick ports that other programs are using
|
/// creating a 'reuseport' socket there. we don't want to pick ports that other programs are using
|
||||||
bound_first_tcp: BTreeMap<u16, Option<(socket2::Socket, socket2::Socket)>>,
|
bound_first_tcp: BTreeMap<u16, (Option<socket2::Socket>, Option<socket2::Socket>)>,
|
||||||
/// TLS handling socket controller
|
/// TLS handling socket controller
|
||||||
tls_acceptor: Option<TlsAcceptor>,
|
tls_acceptor: Option<TlsAcceptor>,
|
||||||
/// Multiplexer record for protocols on low level TCP sockets
|
/// Multiplexer record for protocols on low level TCP sockets
|
||||||
|
@ -85,12 +85,17 @@ impl Network {
|
|||||||
if inner.bound_first_udp.contains_key(&udp_port) {
|
if inner.bound_first_udp.contains_key(&udp_port) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for ipv6
|
||||||
|
let has_v6 = is_ipv6_supported();
|
||||||
|
|
||||||
// If the address is specified, only use the specified port and fail otherwise
|
// If the address is specified, only use the specified port and fail otherwise
|
||||||
let mut bound_first_socket_v4 = None;
|
let mut bound_first_socket_v4 = None;
|
||||||
let mut bound_first_socket_v6 = None;
|
let mut bound_first_socket_v6 = None;
|
||||||
if let Ok(bfs4) =
|
if let Ok(bfs4) =
|
||||||
new_bound_first_udp_socket(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), udp_port))
|
new_bound_first_udp_socket(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), udp_port))
|
||||||
{
|
{
|
||||||
|
if has_v6 {
|
||||||
if let Ok(bfs6) = new_bound_first_udp_socket(SocketAddr::new(
|
if let Ok(bfs6) = new_bound_first_udp_socket(SocketAddr::new(
|
||||||
IpAddr::V6(Ipv6Addr::UNSPECIFIED),
|
IpAddr::V6(Ipv6Addr::UNSPECIFIED),
|
||||||
udp_port,
|
udp_port,
|
||||||
@ -98,24 +103,26 @@ impl Network {
|
|||||||
bound_first_socket_v4 = Some(bfs4);
|
bound_first_socket_v4 = Some(bfs4);
|
||||||
bound_first_socket_v6 = Some(bfs6);
|
bound_first_socket_v6 = Some(bfs6);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
bound_first_socket_v4 = Some(bfs4);
|
||||||
}
|
}
|
||||||
if let (Some(bfs4), Some(bfs6)) = (bound_first_socket_v4, bound_first_socket_v6) {
|
}
|
||||||
|
|
||||||
|
if bound_first_socket_v4.is_none() && (has_v6 && bound_first_socket_v6.is_none()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(windows)] {
|
if #[cfg(windows)] {
|
||||||
// On windows, drop the socket. This is a race condition, but there's
|
// On windows, drop the socket. This is a race condition, but there's
|
||||||
// no way around it. This isn't for security anyway, it's to prevent multiple copies of the
|
// no way around it. This isn't for security anyway, it's to prevent multiple copies of the
|
||||||
// app from binding on the same port.
|
// app from binding on the same port.
|
||||||
drop(bfs4);
|
inner.bound_first_udp.insert(udp_port, (None, None));
|
||||||
drop(bfs6);
|
|
||||||
inner.bound_first_udp.insert(udp_port, None);
|
|
||||||
} else {
|
} else {
|
||||||
inner.bound_first_udp.insert(udp_port, Some((bfs4, bfs6)));
|
inner.bound_first_udp.insert(udp_port, (bound_first_socket_v4, bound_first_socket_v6));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bind_first_tcp_port(&self, tcp_port: u16) -> bool {
|
fn bind_first_tcp_port(&self, tcp_port: u16) -> bool {
|
||||||
@ -123,12 +130,17 @@ impl Network {
|
|||||||
if inner.bound_first_tcp.contains_key(&tcp_port) {
|
if inner.bound_first_tcp.contains_key(&tcp_port) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for ipv6
|
||||||
|
let has_v6 = is_ipv6_supported();
|
||||||
|
|
||||||
// If the address is specified, only use the specified port and fail otherwise
|
// If the address is specified, only use the specified port and fail otherwise
|
||||||
let mut bound_first_socket_v4 = None;
|
let mut bound_first_socket_v4 = None;
|
||||||
let mut bound_first_socket_v6 = None;
|
let mut bound_first_socket_v6 = None;
|
||||||
if let Ok(bfs4) =
|
if let Ok(bfs4) =
|
||||||
new_bound_first_tcp_socket(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), tcp_port))
|
new_bound_first_tcp_socket(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), tcp_port))
|
||||||
{
|
{
|
||||||
|
if has_v6 {
|
||||||
if let Ok(bfs6) = new_bound_first_tcp_socket(SocketAddr::new(
|
if let Ok(bfs6) = new_bound_first_tcp_socket(SocketAddr::new(
|
||||||
IpAddr::V6(Ipv6Addr::UNSPECIFIED),
|
IpAddr::V6(Ipv6Addr::UNSPECIFIED),
|
||||||
tcp_port,
|
tcp_port,
|
||||||
@ -136,24 +148,26 @@ impl Network {
|
|||||||
bound_first_socket_v4 = Some(bfs4);
|
bound_first_socket_v4 = Some(bfs4);
|
||||||
bound_first_socket_v6 = Some(bfs6);
|
bound_first_socket_v6 = Some(bfs6);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
bound_first_socket_v4 = Some(bfs4);
|
||||||
}
|
}
|
||||||
if let (Some(bfs4), Some(bfs6)) = (bound_first_socket_v4, bound_first_socket_v6) {
|
}
|
||||||
|
|
||||||
|
if bound_first_socket_v4.is_none() && (has_v6 && bound_first_socket_v6.is_none()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(windows)] {
|
if #[cfg(windows)] {
|
||||||
// On windows, drop the socket. This is a race condition, but there's
|
// On windows, drop the socket. This is a race condition, but there's
|
||||||
// no way around it. This isn't for security anyway, it's to prevent multiple copies of the
|
// no way around it. This isn't for security anyway, it's to prevent multiple copies of the
|
||||||
// app from binding on the same port.
|
// app from binding on the same port.
|
||||||
drop(bfs4);
|
inner.bound_first_tcp.insert(tcp_port, (None, None));
|
||||||
drop(bfs6);
|
|
||||||
inner.bound_first_tcp.insert(tcp_port, None);
|
|
||||||
} else {
|
} else {
|
||||||
inner.bound_first_tcp.insert(tcp_port, Some((bfs4, bfs6)));
|
inner.bound_first_tcp.insert(tcp_port, (bound_first_socket_v4, bound_first_socket_v6));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn free_bound_first_ports(&self) {
|
pub(super) fn free_bound_first_ports(&self) {
|
||||||
@ -204,10 +218,7 @@ impl Network {
|
|||||||
if listen_address.is_empty() {
|
if listen_address.is_empty() {
|
||||||
// If listen address is empty, find us a port iteratively
|
// If listen address is empty, find us a port iteratively
|
||||||
let port = self.find_available_udp_port(5150)?;
|
let port = self.find_available_udp_port(5150)?;
|
||||||
let ip_addrs = vec![
|
let ip_addrs = available_unspecified_addresses();
|
||||||
IpAddr::V4(Ipv4Addr::UNSPECIFIED),
|
|
||||||
IpAddr::V6(Ipv6Addr::UNSPECIFIED),
|
|
||||||
];
|
|
||||||
Ok((port, ip_addrs))
|
Ok((port, ip_addrs))
|
||||||
} else {
|
} else {
|
||||||
// If no address is specified, but the port is, use ipv4 and ipv6 unspecified
|
// If no address is specified, but the port is, use ipv4 and ipv6 unspecified
|
||||||
@ -227,10 +238,7 @@ impl Network {
|
|||||||
if listen_address.is_empty() {
|
if listen_address.is_empty() {
|
||||||
// If listen address is empty, find us a port iteratively
|
// If listen address is empty, find us a port iteratively
|
||||||
let port = self.find_available_tcp_port(5150)?;
|
let port = self.find_available_tcp_port(5150)?;
|
||||||
let ip_addrs = vec![
|
let ip_addrs = available_unspecified_addresses();
|
||||||
IpAddr::V4(Ipv4Addr::UNSPECIFIED),
|
|
||||||
IpAddr::V6(Ipv6Addr::UNSPECIFIED),
|
|
||||||
];
|
|
||||||
Ok((port, ip_addrs))
|
Ok((port, ip_addrs))
|
||||||
} else {
|
} else {
|
||||||
// If no address is specified, but the port is, use ipv4 and ipv6 unspecified
|
// If no address is specified, but the port is, use ipv4 and ipv6 unspecified
|
||||||
|
@ -345,9 +345,14 @@ impl Network {
|
|||||||
outbound.insert(ProtocolType::WSS);
|
outbound.insert(ProtocolType::WSS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX: See issue #92
|
let supported_address_types: AddressTypeSet = if is_ipv6_supported() {
|
||||||
let family_global = AddressTypeSet::from(AddressType::IPV4);
|
AddressType::IPV4 | AddressType::IPV6
|
||||||
let family_local = AddressTypeSet::from(AddressType::IPV4);
|
} else {
|
||||||
|
AddressType::IPV4.into()
|
||||||
|
};
|
||||||
|
|
||||||
|
let family_global = supported_address_types;
|
||||||
|
let family_local = supported_address_types;
|
||||||
|
|
||||||
let public_internet_capabilities = {
|
let public_internet_capabilities = {
|
||||||
PUBLIC_INTERNET_CAPABILITIES
|
PUBLIC_INTERNET_CAPABILITIES
|
||||||
|
@ -239,13 +239,41 @@ pub fn compatible_unspecified_socket_addr(socket_addr: &SocketAddr) -> SocketAdd
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(not(target_arch = "wasm32"))] {
|
||||||
|
use std::net::UdpSocket;
|
||||||
|
|
||||||
|
static IPV6_IS_SUPPORTED: Mutex<Option<bool>> = Mutex::new(None);
|
||||||
|
|
||||||
|
pub fn is_ipv6_supported() -> bool {
|
||||||
|
let mut opt_supp = IPV6_IS_SUPPORTED.lock();
|
||||||
|
if let Some(supp) = *opt_supp {
|
||||||
|
return supp;
|
||||||
|
}
|
||||||
|
// Not exhaustive but for our use case it should be sufficient. If no local ports are available for binding, Veilid isn't going to work anyway :P
|
||||||
|
let supp = UdpSocket::bind(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 0, 0, 0)).is_ok();
|
||||||
|
*opt_supp = Some(supp);
|
||||||
|
supp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn available_unspecified_addresses() -> Vec<IpAddr> {
|
||||||
|
if is_ipv6_supported() {
|
||||||
|
vec![
|
||||||
|
IpAddr::V4(Ipv4Addr::UNSPECIFIED),
|
||||||
|
IpAddr::V6(Ipv6Addr::UNSPECIFIED),
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
vec![IpAddr::V4(Ipv4Addr::UNSPECIFIED)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn listen_address_to_socket_addrs(listen_address: &str) -> Result<Vec<SocketAddr>, String> {
|
pub fn listen_address_to_socket_addrs(listen_address: &str) -> Result<Vec<SocketAddr>, String> {
|
||||||
// If no address is specified, but the port is, use ipv4 and ipv6 unspecified
|
// If no address is specified, but the port is, use ipv4 and ipv6 unspecified
|
||||||
// If the address is specified, only use the specified port and fail otherwise
|
// If the address is specified, only use the specified port and fail otherwise
|
||||||
let ip_addrs = [
|
|
||||||
IpAddr::V4(Ipv4Addr::UNSPECIFIED),
|
let ip_addrs = available_unspecified_addresses();
|
||||||
IpAddr::V6(Ipv6Addr::UNSPECIFIED),
|
|
||||||
];
|
|
||||||
|
|
||||||
Ok(if let Some(portstr) = listen_address.strip_prefix(':') {
|
Ok(if let Some(portstr) = listen_address.strip_prefix(':') {
|
||||||
let port = portstr
|
let port = portstr
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#![cfg(target_arch = "wasm32")]
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use core::sync::atomic::{AtomicI8, Ordering};
|
use core::sync::atomic::{AtomicI8, Ordering};
|
||||||
use js_sys::{global, Reflect};
|
use js_sys::{global, Reflect};
|
||||||
@ -58,3 +60,25 @@ pub struct JsValueError(String);
|
|||||||
pub fn map_jsvalue_error(x: JsValue) -> JsValueError {
|
pub fn map_jsvalue_error(x: JsValue) -> JsValueError {
|
||||||
JsValueError(x.as_string().unwrap_or_default())
|
JsValueError(x.as_string().unwrap_or_default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static IPV6_IS_SUPPORTED: Mutex<Option<bool>> = Mutex::new(None);
|
||||||
|
|
||||||
|
pub fn is_ipv6_supported() -> bool {
|
||||||
|
let mut opt_supp = IPV6_IS_SUPPORTED.lock();
|
||||||
|
if let Some(supp) = *opt_supp {
|
||||||
|
return supp;
|
||||||
|
}
|
||||||
|
// let supp = match UdpSocket::bind(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 0, 0, 0)) {
|
||||||
|
// Ok(_) => true,
|
||||||
|
// Err(e) => !matches!(
|
||||||
|
// e.kind(),
|
||||||
|
// std::io::ErrorKind::AddrNotAvailable | std::io::ErrorKind::Unsupported
|
||||||
|
// ),
|
||||||
|
// };
|
||||||
|
|
||||||
|
// XXX: See issue #92
|
||||||
|
let supp = false;
|
||||||
|
|
||||||
|
*opt_supp = Some(supp);
|
||||||
|
supp
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user