Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: improve connectivity #1128

Merged
merged 33 commits into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
3062781
fix(conn): send full ping if no addrs are not available
dignifiedquire Jun 22, 2023
60fe5bc
fix: handle disco messages on derp
dignifiedquire Jun 22, 2023
75f351c
fix: stop stayinalive once session times out
dignifiedquire Jun 23, 2023
d075cab
cleanup pings more regularly
dignifiedquire Jun 23, 2023
5e9c8f7
fix typo
dignifiedquire Jun 23, 2023
1044155
ci: enable skipped tests
dignifiedquire Jun 23, 2023
3a15966
ci: skip for real
dignifiedquire Jun 23, 2023
fff1563
fix: ensure derp hostnames are treated consistently
dignifiedquire Jun 23, 2023
652873b
ci: debug
dignifiedquire Jun 23, 2023
fc9e47f
less trust
dignifiedquire Jun 23, 2023
05498f0
revert trust
dignifiedquire Jun 23, 2023
3e5363c
fix(netcheck): hostname handling for captive portal
dignifiedquire Jun 23, 2023
06ab62f
fix(derp): don't panic on region check
dignifiedquire Jun 23, 2023
64a0503
refactor ping handling
dignifiedquire Jun 23, 2023
d786d94
ci: add back integration flag
dignifiedquire Jun 23, 2023
c169e73
refactor: remove unused fields from `cfg::Node`
dignifiedquire Jun 26, 2023
80dabeb
refactor: improve initial udp addr selection
dignifiedquire Jun 26, 2023
89a809d
fix: derp backup addr
dignifiedquire Jun 26, 2023
77d7be1
fix: track received ips as candidate endpoints
dignifiedquire Jun 26, 2023
117df0b
fix: change when pings are sent
dignifiedquire Jun 26, 2023
380b216
always directly ping best_addr
dignifiedquire Jun 26, 2023
9984d4a
rm log file
dignifiedquire Jun 26, 2023
13444a0
improve trust setup
dignifiedquire Jun 26, 2023
7db8162
fix: ensure full pings are done and best_addr is cleaned up
dignifiedquire Jun 26, 2023
e15da27
happy clippy
dignifiedquire Jun 26, 2023
a3c0d56
fix(endpoint): use recent pong instead of now
dignifiedquire Jun 26, 2023
2c41eed
fix: improve full ping and unknown key handling
dignifiedquire Jun 26, 2023
0cecc4b
show logging on failed cli tests & adjust `candidate_endpoint`
ramfox Jun 27, 2023
e53b5fe
Merge pull request #1136 from n0-computer/ramfox/fix-odd-issues
dignifiedquire Jun 27, 2023
036c44a
simplify ping logic
dignifiedquire Jun 27, 2023
0f3edde
refactor: use a timer to handle ping timeouts
dignifiedquire Jun 27, 2023
2b15243
ci: remove debug flag
dignifiedquire Jun 27, 2023
ab9ef90
test: do not assume no packets get lost
dignifiedquire Jun 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ jobs:
sudo kill -9 $(pgrep ovs)
sudo mn --clean
sudo python3 main.py --integration sims/iroh/iroh.json
sudo python3 main.py --integration --skip intg_derper__1_to_1_NAT_provide,intg_derper__1_to_1_NAT_both sims/integration
sudo python3 main.py --integration --debug sims/integration
dignifiedquire marked this conversation as resolved.
Show resolved Hide resolved

- name: Setup Environment (PR)
if: ${{ github.event_name == 'pull_request' }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/netsim.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ jobs:
if [ -z "${c}" ];
then
sudo python3 main.py sims/iroh
sudo python3 main.py --skip intg_derper__1_to_1_NAT_provide,intg_derper__1_to_1_NAT_both sims/integration
sudo python3 main.py sims/integration
else
echo $c >> custom_sim.json
sudo python3 main.py custom_sim.json
Expand Down Expand Up @@ -197,4 +197,4 @@ jobs:
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer ${{secrets.METRO_TOKEN}}" --data "$metro_data" ${{secrets.METRO_ENDPOINT}}
d=$(cat report_metro_integration.txt)
metro_data=$(printf "%s\n " "$d")
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer ${{secrets.METRO_TOKEN}}" --data "$metro_data" ${{secrets.METRO_ENDPOINT}}
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer ${{secrets.METRO_TOKEN}}" --data "$metro_data" ${{secrets.METRO_ENDPOINT}}
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions iroh-net/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ tokio = { version = "1", features = ["io-util", "sync", "rt", "net", "fs"] }
tokio-util = { version = "0.7", features = ["io-util", "io"] }
tokio-rustls = { version = "0.24" }
tokio-rustls-acme = { version = "0.1" }
url = { version = "2.4", features = ["serde"] }
webpki = { version = "0.22", features = ["std"] }
webpki-roots = "0.23.0"
wg = "0.3.1"
Expand Down
8 changes: 1 addition & 7 deletions iroh-net/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{
net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
sync::Arc,
time::{Duration, Instant},
time::Duration,
};

use anyhow::{Context, Result};
Expand Down Expand Up @@ -115,12 +115,6 @@ pub async fn dial_peer(
key: node_key.clone(),
endpoints,
derp: Some(SocketAddr::new(DERP_MAGIC_IP, DEFAULT_DERP_REGION)),
created: Instant::now(),
hostinfo: hp::hostinfo::Hostinfo::default(),
keep_alive: false,
expired: false,
online: None,
last_seen: None,
}],
})
.await?;
Expand Down
19 changes: 1 addition & 18 deletions iroh-net/src/hp/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ use std::{
collections::HashMap,
fmt::Display,
net::{IpAddr, Ipv4Addr, SocketAddr},
time::Instant,
};

use super::{hostinfo::Hostinfo, key};
use super::key;

/// Fake WireGuard endpoint IP address that means to
/// use DERP. When used (in the Node.DERP field), the port number of
Expand Down Expand Up @@ -169,20 +168,4 @@ pub struct Node {
///
/// If this nodes expected to be reachable via DERP relaying.
pub derp: Option<SocketAddr>,
pub hostinfo: Hostinfo,
pub created: Instant,

/// When the node was last online. It is not
/// updated when Online is true. It is nil if the current
/// node doesn't have permission to know, or the node has never been online.
pub last_seen: Option<Instant>,

/// Whether the node is currently connected to the
/// coordination server. A value of None means unknown, or the current node doesn't have permission to know.
pub online: Option<bool>,

/// Open and keep open a connection to this peer
pub keep_alive: bool,

pub expired: bool,
}
4 changes: 2 additions & 2 deletions iroh-net/src/hp/derp/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ mod tests {
nodes: vec![DerpNode {
name: "test_node".to_string(),
region_id: 1,
host_name: "localhost".to_string(),
host_name: "http://localhost".parse().unwrap(),
stun_only: false,
stun_port: 0,
stun_test_ip: None,
Expand Down Expand Up @@ -216,7 +216,7 @@ mod tests {
nodes: vec![DerpNode {
name: "test_node".to_string(),
region_id: 1,
host_name: "localhost".to_string(),
host_name: "https://localhost".parse().unwrap(),
stun_only: false,
stun_port: 0,
stun_test_ip: None,
Expand Down
107 changes: 64 additions & 43 deletions iroh-net/src/hp/derp/http/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ use futures::future::BoxFuture;
use hyper::upgrade::Upgraded;
use hyper::{header::UPGRADE, Body, Request};
use rand::Rng;
use reqwest::Url;
use tokio::net::TcpStream;
use tokio::sync::oneshot;
use tokio::sync::Mutex;
use tokio::task::JoinSet;
use tracing::{debug, instrument, warn};
use url::Url;

use crate::hp::derp::client_conn::Io;
use crate::hp::derp::{
Expand Down Expand Up @@ -70,8 +70,8 @@ pub enum ClientError {
PingTimeout,
#[error("cannot acknowledge pings")]
CannotAckPings,
#[error("invalid url")]
InvalidUrl,
#[error("invalid url: {0}")]
InvalidUrl(String),
#[error("dns: {0:?}")]
Dns(Option<trust_dns_resolver::error::ResolveError>),
}
Expand Down Expand Up @@ -157,7 +157,7 @@ impl ClientBuilder {
self
}

/// S returns if we should prefer ipv6
/// Returns if we should prefer ipv6
/// it replaces the derphttp.AddressFamilySelector we pass
/// It provides the hint as to whether in an IPv4-vs-IPv6 race that
/// IPv4 should be held back a bit to give IPv6 a better-than-50/50
Expand Down Expand Up @@ -306,7 +306,8 @@ impl Client {
if let Some(get_region) = &self.inner.get_region {
let region = get_region()
.await
.expect("Cannot connection client: DERP region is unknown");
.ok_or_else(|| ClientError::DerpRegionNotAvail)?;

return Ok(region);
}
Err(ClientError::DerpRegionNotAvail)
Expand All @@ -323,7 +324,9 @@ impl Client {
.and_then(|s| rustls::ServerName::try_from(s).ok());
}
if let Some(node) = node {
return rustls::ServerName::try_from(node.host_name.as_str()).ok();
if let Some(host) = node.host_name.host_str() {
return rustls::ServerName::try_from(host).ok();
}
}

None
Expand All @@ -344,22 +347,33 @@ impl Client {
None
}

fn use_https(&self) -> bool {
fn use_https(&self, node: Option<&DerpNode>) -> bool {
// only disable https if we are explicitly dialing a http url
if let Some(true) = self.inner.url.as_ref().map(|url| url.scheme() == "http") {
return false;
}
if let Some(node) = node {
if node.host_name.scheme() == "http" {
return false;
}
}
true
}

async fn connect_0(&self) -> Result<DerpClient, ClientError> {
debug!("connect_0");
let region = self.current_region().await?;
debug!("connect_0 region: {:?}", region);
let url = self.url();
let is_test_url = url
.as_ref()
.map(|url| url.as_str().ends_with(".invalid"))
.unwrap_or_default();

debug!("connect_0 url: {:?}, is_test_url: {}", url, is_test_url);

let (tcp_stream, derp_node) = if self.url().is_some() {
let (tcp_stream, derp_node) = if url.is_some() && !is_test_url {
(self.dial_url().await?, None)
} else {
let region = self.current_region().await?;
let (tcp_stream, derp_node) = self.dial_region(region).await?;
(tcp_stream, Some(derp_node))
};
Expand All @@ -374,7 +388,7 @@ impl Client {
.body(Body::empty())
.unwrap();

let res = if self.use_https() {
let res = if self.use_https(derp_node.as_ref()) {
debug!("Starting TLS handshake");
// TODO: review TLS config
let mut roots = rustls::RootCertStore::empty();
Expand All @@ -398,7 +412,7 @@ impl Client {
let tls_connector: tokio_rustls::TlsConnector = Arc::new(config).into();
let hostname = self
.tls_servername(derp_node.as_ref())
.ok_or_else(|| ClientError::InvalidUrl)?;
.ok_or_else(|| ClientError::InvalidUrl("no tls servername".into()))?;
let tls_stream = tls_connector.connect(hostname, tcp_stream).await?;
debug!("tls_connector connect success");
let (mut request_sender, connection) = hyper::client::conn::Builder::new()
Expand Down Expand Up @@ -494,27 +508,29 @@ impl Client {
}

async fn dial_url(&self) -> Result<TcpStream, ClientError> {
let host = if let Some(host_str) = self.url().and_then(|url| url.host_str()) {
host_str
} else {
return Err(ClientError::InvalidUrl);
};
let host = self.url().and_then(|url| url.host()).ok_or_else(|| {
ClientError::InvalidUrl(format!("missing host from {:?}", self.url()))
})?;

debug!("dial url: {}", host);
let dst_ip: IpAddr = if let Ok(ip) = host.parse() {
// Already a valid IP address
ip
} else {
// Need to do a DNS lookup
let addr = DNS_RESOLVER
.lookup_ip(host)
.await
.map_err(|e| ClientError::Dns(Some(e)))?
.iter()
.next();
addr.ok_or_else(|| ClientError::Dns(None))?
let dst_ip = match host {
url::Host::Domain(hostname) => {
// Need to do a DNS lookup
let addr = DNS_RESOLVER
.lookup_ip(hostname)
.await
.map_err(|e| ClientError::Dns(Some(e)))?
.iter()
.next();
addr.ok_or_else(|| ClientError::Dns(None))?
}
url::Host::Ipv4(ip) => IpAddr::V4(ip),
url::Host::Ipv6(ip) => IpAddr::V6(ip),
};

let port = self.url_port().ok_or_else(|| ClientError::InvalidUrl)?;
let port = self
.url_port()
.ok_or_else(|| ClientError::InvalidUrl("missing url port".into()))?;
let addr = SocketAddr::new(dst_ip, port);

tracing::error!("connecting to {}", addr);
Expand Down Expand Up @@ -620,18 +636,23 @@ impl Client {
UseIp::Ipv4(UseIpv4::Some(addr)) => addr.into(),
UseIp::Ipv6(UseIpv6::Some(addr)) => addr.into(),
_ => {
if let Ok(ip) = node.host_name.parse() {
// Already a valid IP address
ip
} else {
// Need to do a DNS lookup
let addr = DNS_RESOLVER
.lookup_ip(&node.host_name)
.await
.map_err(|e| ClientError::Dns(Some(e)))?
.iter()
.next();
addr.ok_or_else(|| ClientError::Dns(None))?
let host = node
.host_name
.host()
.ok_or_else(|| ClientError::InvalidUrl("missing host".into()))?;
match host {
url::Host::Domain(domain) => {
// Need to do a DNS lookup
let addr = DNS_RESOLVER
.lookup_ip(domain)
.await
.map_err(|e| ClientError::Dns(Some(e)))?
.iter()
.next();
addr.ok_or_else(|| ClientError::Dns(None))?
}
url::Host::Ipv4(ip) => IpAddr::V4(ip),
url::Host::Ipv6(ip) => IpAddr::V6(ip),
}
}
};
Expand Down Expand Up @@ -900,7 +921,7 @@ mod tests {
nodes: vec![DerpNode {
name: "test_node".to_string(),
region_id: 1,
host_name: "bad.url".into(),
host_name: "http://bad.url".parse().unwrap(),
stun_only: false,
stun_port: 0,
stun_test_ip: None,
Expand Down
5 changes: 3 additions & 2 deletions iroh-net/src/hp/derp/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::{
};

use serde::{Deserialize, Serialize};
use url::Url;

/// Configuration of all the Derp servers that can be used.
#[derive(Debug, Default, Clone, PartialEq, Eq)]
Expand All @@ -24,7 +25,7 @@ impl DerpMap {

/// Creates a new [`DerpMap`] with a single Derp server configured.
pub fn default_from_node(
host_name: String,
host_name: Url,
stun_port: u16,
derp_port: u16,
derp_ipv4: UseIpv4,
Expand Down Expand Up @@ -78,7 +79,7 @@ pub struct DerpRegion {
pub struct DerpNode {
pub name: String,
pub region_id: usize,
pub host_name: String,
pub host_name: Url,
pub stun_only: bool,
pub stun_port: u16,
pub stun_test_ip: Option<IpAddr>,
Expand Down
Loading