client: wait after updating interface before attempting NAT traversal

otherwise, the server-reported IP itself won't have time to check
if a handshake succeeds or not.
pull/172/head
Jake McGinty 2021-11-11 18:34:31 +09:00
parent b0d0ee8565
commit 991c6435c1
4 changed files with 26 additions and 8 deletions

View File

@ -18,7 +18,7 @@ use std::{
net::SocketAddr, net::SocketAddr,
path::{Path, PathBuf}, path::{Path, PathBuf},
thread, thread,
time::Duration, time::{Duration, Instant},
}; };
use structopt::{clap::AppSettings, StructOpt}; use structopt::{clap::AppSettings, StructOpt};
use wireguard_control::{Device, DeviceUpdate, InterfaceName, PeerConfigBuilder, PeerInfo}; use wireguard_control::{Device, DeviceUpdate, InterfaceName, PeerConfigBuilder, PeerInfo};
@ -546,6 +546,7 @@ fn fetch(
} else { } else {
log::info!("{}", "peers are already up to date.".green()); log::info!("{}", "peers are already up to date.".green());
} }
let interface_updated_time = Instant::now();
store.set_cidrs(cidrs); store.set_cidrs(cidrs);
store.update_peers(&peers)?; store.update_peers(&peers)?;
@ -559,7 +560,6 @@ fn fetch(
candidates.len(), candidates.len(),
if candidates.len() == 1 { "" } else { "es" } if candidates.len() == 1 { "" } else { "es" }
); );
log::debug!("candidates: {:?}", candidates);
match Api::new(&config.server).http_form::<_, ()>("PUT", "/user/candidates", &candidates) { match Api::new(&config.server).http_form::<_, ()>("PUT", "/user/candidates", &candidates) {
Err(ureq::Error::Status(404, _)) => { Err(ureq::Error::Status(404, _)) => {
log::warn!("your network is using an old version of innernet-server that doesn't support NAT traversal candidate reporting.") log::warn!("your network is using an old version of innernet-server that doesn't support NAT traversal candidate reporting.")
@ -567,10 +567,13 @@ fn fetch(
Err(e) => return Err(e.into()), Err(e) => return Err(e.into()),
_ => {}, _ => {},
} }
log::debug!("reported candidates: {:?}", candidates);
log::debug!("viable ICE candidates: {:?}", candidates);
let mut nat_traverse = NatTraverse::new(interface, network.backend, &modifications)?; let mut nat_traverse = NatTraverse::new(interface, network.backend, &modifications)?;
if !nat_traverse.is_finished() {
thread::sleep(nat::STEP_INTERVAL - interface_updated_time.elapsed());
}
loop { loop {
if nat_traverse.is_finished() { if nat_traverse.is_finished() {
break; break;

View File

@ -12,7 +12,7 @@ use shared::{
}; };
use wireguard_control::{Backend, Device, DeviceUpdate, InterfaceName, Key, PeerConfigBuilder}; use wireguard_control::{Backend, Device, DeviceUpdate, InterfaceName, Key, PeerConfigBuilder};
const STEP_INTERVAL: Duration = Duration::from_secs(5); pub const STEP_INTERVAL: Duration = Duration::from_secs(5);
pub struct NatTraverse<'a> { pub struct NatTraverse<'a> {
interface: &'a InterfaceName, interface: &'a InterfaceName,
@ -26,6 +26,7 @@ impl<'a> NatTraverse<'a> {
backend: Backend, backend: Backend,
diffs: &[PeerDiff], diffs: &[PeerDiff],
) -> Result<Self, Error> { ) -> Result<Self, Error> {
// Filter out removed peers from diffs list.
let mut remaining: Vec<_> = diffs.iter().filter_map(|diff| diff.new).cloned().collect(); let mut remaining: Vec<_> = diffs.iter().filter_map(|diff| diff.new).cloned().collect();
for peer in &mut remaining { for peer in &mut remaining {
@ -97,6 +98,9 @@ impl<'a> NatTraverse<'a> {
// Set all peers' endpoints to their next available candidate. // Set all peers' endpoints to their next available candidate.
let candidate_updates = self.remaining.iter_mut().filter_map(|peer| { let candidate_updates = self.remaining.iter_mut().filter_map(|peer| {
let endpoint = peer.candidates.pop(); let endpoint = peer.candidates.pop();
if let Some(endpoint) = &endpoint {
log::debug!("trying endpoint {} for peer {}", endpoint, peer.name);
}
set_endpoint(&peer.public_key, endpoint.as_ref()) set_endpoint(&peer.public_key, endpoint.as_ref())
}); });

View File

@ -5,7 +5,7 @@ use dialoguer::{theme::ColorfulTheme, Input};
use indoc::printdoc; use indoc::printdoc;
use publicip::Preference; use publicip::Preference;
use rusqlite::{params, Connection}; use rusqlite::{params, Connection};
use shared::{CidrContents, Endpoint, PERSISTENT_KEEPALIVE_INTERVAL_SECS, PeerContents, prompts}; use shared::{prompts, CidrContents, Endpoint, PeerContents, PERSISTENT_KEEPALIVE_INTERVAL_SECS};
use wireguard_control::KeyPair; use wireguard_control::KeyPair;
fn create_database<P: AsRef<Path>>( fn create_database<P: AsRef<Path>>(

View File

@ -3,7 +3,16 @@ use ipnetwork::IpNetwork;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::Regex; use regex::Regex;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{fmt::{self, Display, Formatter}, io, net::{IpAddr, SocketAddr, ToSocketAddrs}, ops::{Deref, DerefMut}, path::Path, str::FromStr, time::{Duration, SystemTime}, vec}; use std::{
fmt::{self, Display, Formatter},
io,
net::{IpAddr, SocketAddr, ToSocketAddrs},
ops::{Deref, DerefMut},
path::Path,
str::FromStr,
time::{Duration, SystemTime},
vec,
};
use structopt::StructOpt; use structopt::StructOpt;
use url::Host; use url::Host;
use wireguard_control::{ use wireguard_control::{
@ -25,7 +34,9 @@ impl FromStr for Interface {
if !Hostname::is_valid(name) { if !Hostname::is_valid(name) {
Err(InvalidInterfaceName::InvalidChars) Err(InvalidInterfaceName::InvalidChars)
} else { } else {
Ok(Self { name: name.parse()? }) Ok(Self {
name: name.parse()?,
})
} }
} }
} }