use super::*;
use lazy_static::*;
lazy_static! {
static ref BAD_PORTS: BTreeSet<u16> = BTreeSet::from([
1, 7, 9, 11, 13, 15, 17, 19, 20, 21, 22, 23, 25, 37, 42, 43, 53, 77, 79, 87, 95, 101, 102, 103, 104, 109, 110, 111, 113, 115, 117, 119, 123, 135, 139, 143, 179, 389, 427, 465, 512, 513, 514, 515, 526, 530, 531, 532, 540, 548, 556, 563, 587, 601, 636, 993, 995, 2049, 3659, 4045, 6000, 6665, 6666, 6667, 6668, 6669, 6697, ]);
}
pub(super) struct NetworkBindSet {
pub port: u16,
pub addrs: Vec<IpAddr>,
pub search: bool,
}
impl Network {
#[cfg_attr(feature = "instrument", instrument(level = "trace", skip_all, fields(__VEILID_LOG_KEY = self.log_key())))]
fn convert_listen_address_to_bind_set(
&self,
listen_address: String,
) -> EyreResult<NetworkBindSet> {
if listen_address.is_empty() {
let ip_addrs = available_unspecified_addresses();
Ok(NetworkBindSet {
port: 5150,
addrs: ip_addrs,
search: true,
})
} else {
let sockaddrs =
listen_address_to_socket_addrs(&listen_address).map_err(|e| eyre!("{}", e))?;
if sockaddrs.is_empty() {
bail!("No valid listen address: {}", listen_address);
}
let port = sockaddrs[0].port();
if port == 0 {
Ok(NetworkBindSet {
port: 5150,
addrs: sockaddrs.iter().map(|s| s.ip()).collect(),
search: true,
})
} else {
Ok(NetworkBindSet {
port,
addrs: sockaddrs.iter().map(|s| s.ip()).collect(),
search: false,
})
}
}
}
pub(super) fn set_preferred_local_address(inner: &mut NetworkInner, pa: PeerAddress) {
let key = (pa.protocol_type(), pa.address_type());
let sa = pa.socket_addr();
inner.preferred_local_addresses.entry(key).or_insert(sa);
}
#[cfg_attr(feature = "instrument", instrument(level = "trace", skip_all, fields(__VEILID_LOG_KEY = self.log_key())))]
pub(super) fn bind_udp_protocol_handlers(&self) -> EyreResult<StartupDisposition> {
veilid_log!(self trace "UDP: binding protocol handlers");
let config = self.config();
let listen_address = config.network.protocol.udp.listen_address.clone();
let public_address = config.network.protocol.udp.public_address.clone();
let require_inbound_relay = config.network.privacy.require_inbound_relay;
let bind_set = self.convert_listen_address_to_bind_set(listen_address.clone())?;
if bind_set.search {
veilid_log!(self info
"UDP: searching for free port starting with {} on {:?}",
bind_set.port, bind_set.addrs
);
} else {
veilid_log!(self info
"UDP: binding protocol handlers at port {} on {:?}",
bind_set.port, bind_set.addrs
);
}
if !self.create_inbound_udp_protocol_handlers(bind_set)? {
return Ok(StartupDisposition::BindRetry);
};
if !self.create_outbound_udp_protocol_handlers()? {
return Ok(StartupDisposition::BindRetry);
}
self.create_udp_listener_tasks()?;
{
let mut inner = self.inner.lock();
if public_address.is_some()
&& !inner.resolved_detect_address_changes
&& !require_inbound_relay
{
inner.static_public_dial_info.insert(ProtocolType::UDP);
}
}
Ok(StartupDisposition::Success)
}
#[cfg_attr(feature = "instrument", instrument(level = "trace", skip_all, fields(__VEILID_LOG_KEY = self.log_key())))]
pub(super) fn register_udp_dial_info(
&self,
editor_public_internet: &mut RoutingDomainEditorPublicInternet<'_>,
editor_local_network: &mut RoutingDomainEditorLocalNetwork<'_>,
) -> EyreResult<()> {
veilid_log!(self trace "UDP: registering dial info");
let config = self.config();
let public_address = config.network.protocol.udp.public_address.clone();
let resolved_detect_address_changes = self.inner.lock().resolved_detect_address_changes;
let require_inbound_relay = config.network.privacy.require_inbound_relay;
let local_dial_info_list = {
let mut out = vec![];
if let Some(bound_addresses) = {
let inner = self.inner.lock();
inner
.bound_address_per_protocol
.get(&ProtocolType::UDP)
.cloned()
} {
for addr in bound_addresses {
let idi_addrs = self.translate_unspecified_address(addr);
for idi_addr in idi_addrs {
out.push(DialInfo::udp_from_socketaddr(idi_addr));
}
}
}
out.sort();
out.dedup();
out
};
if let (Some(public_address), false) = (public_address.as_ref(), require_inbound_relay) {
let mut public_sockaddrs = public_address
.to_socket_addrs()
.wrap_err(format!("Unable to resolve address: {}", public_address))?;
for pdi_addr in &mut public_sockaddrs {
let pdi = DialInfo::udp_from_socketaddr(pdi_addr);
editor_public_internet.add_dial_info(pdi.clone(), DialInfoClass::Direct);
if self.is_interface_address(pdi_addr.ip()) {
editor_local_network.add_dial_info(
DialInfo::udp_from_socketaddr(pdi_addr),
DialInfoClass::Direct,
);
}
}
}
for di in &local_dial_info_list {
if !resolved_detect_address_changes
&& !require_inbound_relay
&& public_address.is_none()
&& di.address().is_global()
{
editor_public_internet.add_dial_info(di.clone(), DialInfoClass::Direct);
}
editor_local_network.add_dial_info(di.clone(), DialInfoClass::Direct);
}
Ok(())
}
#[cfg_attr(feature = "instrument", instrument(level = "trace", skip_all, fields(__VEILID_LOG_KEY = self.log_key())))]
pub(super) fn start_ws_listeners(&self) -> EyreResult<StartupDisposition> {
veilid_log!(self trace "WS: binding protocol handlers");
let config = self.config();
let listen_address = config.network.protocol.ws.listen_address.clone();
let url = config.network.protocol.ws.url.clone();
let require_inbound_relay = config.network.privacy.require_inbound_relay;
let bind_set = self.convert_listen_address_to_bind_set(listen_address.clone())?;
if bind_set.search {
veilid_log!(self info
"WS: searching for free port starting with {} on {:?}",
bind_set.port, bind_set.addrs
);
} else {
veilid_log!(self info
"WS: binding protocol handlers at port {} on {:?}",
bind_set.port, bind_set.addrs
);
}
if !self.start_tcp_listener(
bind_set,
false,
ProtocolType::WS,
Box::new(|r, t| Box::new(WebsocketProtocolHandler::new(r, t))),
)? {
return Ok(StartupDisposition::BindRetry);
}
{
let mut inner = self.inner.lock();
if url.is_some() && !inner.resolved_detect_address_changes && !require_inbound_relay {
inner.static_public_dial_info.insert(ProtocolType::WS);
}
}
Ok(StartupDisposition::Success)
}
#[cfg_attr(feature = "instrument", instrument(level = "trace", skip_all, fields(__VEILID_LOG_KEY = self.log_key())))]
pub(super) fn register_ws_dial_info(
&self,
editor_public_internet: &mut RoutingDomainEditorPublicInternet<'_>,
editor_local_network: &mut RoutingDomainEditorLocalNetwork<'_>,
) -> EyreResult<()> {
veilid_log!(self trace "WS: registering dial info");
let config = self.config();
let url = config.network.protocol.ws.url.clone();
let path = config.network.protocol.ws.path.clone();
let resolved_detect_address_changes = self.inner.lock().resolved_detect_address_changes;
let require_inbound_relay = config.network.privacy.require_inbound_relay;
let mut registered_addresses: HashSet<IpAddr> = HashSet::new();
let socket_addresses = {
let mut out = vec![];
if let Some(bound_addresses) = {
let inner = self.inner.lock();
inner
.bound_address_per_protocol
.get(&ProtocolType::WS)
.cloned()
} {
for addr in bound_addresses {
for idi_addr in self
.translate_unspecified_address(addr)
.into_iter()
.map(SocketAddress::from_socket_addr)
{
out.push(idi_addr);
}
}
}
out.sort();
out.dedup();
out
};
if let Some(url) = url.as_ref() {
let mut split_url = SplitUrl::from_str(url).wrap_err("couldn't split url")?;
if !split_url.scheme.eq_ignore_ascii_case("ws") {
bail!("WS URL must use 'ws://' scheme");
}
"ws".clone_into(&mut split_url.scheme);
let global_socket_addrs = split_url
.host_port(80)
.to_socket_addrs()
.wrap_err("failed to resolve ws url")?;
for gsa in global_socket_addrs {
let pdi = DialInfo::try_ws(SocketAddress::from_socket_addr(gsa), url.clone())
.wrap_err("try_ws failed")?;
editor_public_internet.add_dial_info(pdi.clone(), DialInfoClass::Direct);
if !registered_addresses.contains(&gsa.ip()) && self.is_interface_address(gsa.ip())
{
editor_local_network.add_dial_info(pdi, DialInfoClass::Direct);
}
registered_addresses.insert(gsa.ip());
}
}
for socket_address in &socket_addresses {
if registered_addresses.contains(&socket_address.ip_addr()) {
continue;
}
let local_url = format!("ws://{}/{}", socket_address, path);
let local_di =
DialInfo::try_ws(*socket_address, local_url).wrap_err("try_ws failed")?;
if !resolved_detect_address_changes
&& !require_inbound_relay
&& url.is_none()
&& local_di.address().is_global()
{
editor_public_internet.add_dial_info(local_di.clone(), DialInfoClass::Direct);
}
editor_local_network.add_dial_info(local_di, DialInfoClass::Direct);
}
Ok(())
}
#[cfg(feature = "enable-protocol-wss")]
#[cfg_attr(feature = "instrument", instrument(level = "trace", skip_all, fields(__VEILID_LOG_KEY = self.log_key())))]
pub(super) async fn start_wss_listeners(&self) -> EyreResult<StartupDisposition> {
veilid_log!(self trace "WSS: binding protocol handlers");
let config = self.config();
let listen_address = config.network.protocol.wss.listen_address.clone();
let url = config.network.protocol.wss.url.clone();
let resolved_detect_address_changes = self.inner.lock().resolved_detect_address_changes;
let require_inbound_relay = config.network.privacy.require_inbound_relay;
let bind_set = self
.convert_listen_address_to_bind_set(listen_address.clone())
.await?;
if bind_set.search {
veilid_log!(self info
"WSS: searching for free port starting with {} on {:?}",
bind_set.port, bind_set.addrs
);
} else {
veilid_log!(self info
"WSS: binding protocol handlers at port {} on {:?}",
bind_set.port, bind_set.addrs
);
}
if !self
.start_tcp_listener(
bind_set,
true,
ProtocolType::WSS,
Box::new(|r, t| Box::new(WebsocketProtocolHandler::new(r, t))),
)
.await?
{
return Ok(StartupDisposition::BindRetry);
}
{
let mut inner = self.inner.lock();
if url.is_some() && !resolved_detect_address_changes && !require_inbound_relay {
inner.static_public_dial_info.insert(ProtocolType::WSS);
}
}
Ok(StartupDisposition::Success)
}
#[cfg(feature = "enable-protocol-wss")]
#[cfg_attr(feature = "instrument", instrument(level = "trace", skip_all, fields(__VEILID_LOG_KEY = self.log_key())))]
pub(super) async fn register_wss_dial_info(
&self,
editor_public_internet: &mut RoutingDomainEditorPublicInternet<'_>,
editor_local_network: &mut RoutingDomainEditorLocalNetwork<'_>,
) -> EyreResult<()> {
veilid_log!(self trace "WSS: registering dialinfo");
let config = self.config();
let url = config.network.protocol.wss.url.clone();
let _detect_address_changes = config.network.detect_address_changes;
let mut registered_addresses: HashSet<IpAddr> = HashSet::new();
if let Some(url) = url.as_ref() {
let mut split_url = SplitUrl::from_str(url)?;
if !split_url.scheme.eq_ignore_ascii_case("wss") {
bail!("WSS URL must use 'wss://' scheme");
}
"wss".clone_into(&mut split_url.scheme);
let global_socket_addrs = split_url
.host_port(443)
.to_socket_addrs()
.wrap_err("failed to resolve wss url")?;
for gsa in global_socket_addrs {
let pdi = DialInfo::try_wss(SocketAddress::from_socket_addr(gsa), url.clone())
.wrap_err("try_wss failed")?;
editor_public_internet.add_dial_info(pdi.clone(), DialInfoClass::Direct);
if !registered_addresses.contains(&gsa.ip()) && self.is_interface_address(gsa.ip())
{
editor_local_network.add_dial_info(pdi, DialInfoClass::Direct);
}
registered_addresses.insert(gsa.ip());
}
} else {
bail!("WSS URL must be specified due to TLS requirements");
}
Ok(())
}
#[cfg_attr(feature = "instrument", instrument(level = "trace", skip_all, fields(__VEILID_LOG_KEY = self.log_key())))]
pub(super) fn start_tcp_listeners(&self) -> EyreResult<StartupDisposition> {
veilid_log!(self trace "TCP: binding protocol handlers");
let config = self.config();
let listen_address = config.network.protocol.tcp.listen_address.clone();
let public_address = config.network.protocol.tcp.public_address.clone();
let resolved_detect_address_changes = self.inner.lock().resolved_detect_address_changes;
let require_inbound_relay = config.network.privacy.require_inbound_relay;
let bind_set = self.convert_listen_address_to_bind_set(listen_address.clone())?;
if bind_set.search {
veilid_log!(self info
"TCP: searching for free port starting with {} on {:?}",
bind_set.port, bind_set.addrs
);
} else {
veilid_log!(self info
"TCP: binding protocol handlers at port {} on {:?}",
bind_set.port, bind_set.addrs
);
}
if !self.start_tcp_listener(
bind_set,
false,
ProtocolType::TCP,
Box::new(|c, _| Box::new(RawTcpProtocolHandler::new(c))),
)? {
return Ok(StartupDisposition::BindRetry);
}
{
let mut inner = self.inner.lock();
if public_address.is_some()
&& !resolved_detect_address_changes
&& !require_inbound_relay
{
inner.static_public_dial_info.insert(ProtocolType::TCP);
}
}
Ok(StartupDisposition::Success)
}
#[cfg_attr(feature = "instrument", instrument(level = "trace", skip_all, fields(__VEILID_LOG_KEY = self.log_key())))]
pub(super) fn register_tcp_dial_info(
&self,
editor_public_internet: &mut RoutingDomainEditorPublicInternet<'_>,
editor_local_network: &mut RoutingDomainEditorLocalNetwork<'_>,
) -> EyreResult<()> {
veilid_log!(self trace "TCP: registering dialinfo");
let config = self.config();
let public_address = config.network.protocol.tcp.public_address.clone();
let resolved_detect_address_changes = self.inner.lock().resolved_detect_address_changes;
let require_inbound_relay = config.network.privacy.require_inbound_relay;
let mut registered_addresses: HashSet<IpAddr> = HashSet::new();
let socket_addresses = {
let mut out = vec![];
if let Some(bound_addresses) = {
let inner = self.inner.lock();
inner
.bound_address_per_protocol
.get(&ProtocolType::TCP)
.cloned()
} {
for addr in bound_addresses {
for idi_addr in self
.translate_unspecified_address(addr)
.into_iter()
.map(SocketAddress::from_socket_addr)
{
out.push(idi_addr);
}
}
}
out.sort();
out.dedup();
out
};
if let (Some(public_address), false) = (public_address.as_ref(), require_inbound_relay) {
let mut public_sockaddrs = public_address
.to_socket_addrs()
.wrap_err("failed to resolve tcp address")?;
for pdi_addr in &mut public_sockaddrs {
if registered_addresses.contains(&pdi_addr.ip()) {
continue;
}
let pdi = DialInfo::tcp_from_socketaddr(pdi_addr);
editor_public_internet.add_dial_info(pdi.clone(), DialInfoClass::Direct);
if self.is_interface_address(pdi_addr.ip()) {
editor_local_network.add_dial_info(pdi, DialInfoClass::Direct);
}
}
}
for socket_address in &socket_addresses {
let di = DialInfo::tcp(*socket_address);
if !resolved_detect_address_changes
&& !require_inbound_relay
&& public_address.is_none()
&& di.address().is_global()
{
editor_public_internet.add_dial_info(di.clone(), DialInfoClass::Direct);
}
editor_local_network.add_dial_info(di.clone(), DialInfoClass::Direct);
registered_addresses.insert(socket_address.ip_addr());
}
Ok(())
}
}