mirror of
https://github.com/tonarino/innernet.git
synced 2024-11-24 08:42:33 +02:00
server: report local candidates for peers to connect (#151)
Before, only clients would report local addresses for NAT traversal. Servers should too! This will be helpful in common situations when the server is run inside the same LAN as other peers, and there's no NAT hairpinning enabled (or possible) on the router. closes #146
This commit is contained in:
parent
df877d2de8
commit
cf3510918a
@ -4,6 +4,7 @@ use dialoguer::{Confirm, Input};
|
||||
use hostsfile::HostsBuilder;
|
||||
use indoc::eprintdoc;
|
||||
use shared::{
|
||||
get_local_addrs,
|
||||
interface_config::InterfaceConfig,
|
||||
prompts,
|
||||
wg::{DeviceExt, PeerInfoExt},
|
||||
@ -448,7 +449,7 @@ fn redeem_invite(
|
||||
target_conf.to_string_lossy().yellow()
|
||||
);
|
||||
|
||||
log::info!("Changing keys and waiting for server's WireGuard interface to transition.",);
|
||||
log::info!("Changing keys and waiting 5s for server's WireGuard interface to transition.",);
|
||||
DeviceUpdate::new()
|
||||
.set_private_key(keypair.private)
|
||||
.apply(iface, network.backend)
|
||||
@ -550,10 +551,8 @@ fn fetch(
|
||||
store.update_peers(&peers)?;
|
||||
store.write().with_str(interface.to_string())?;
|
||||
|
||||
let candidates = wg::get_local_addrs()?
|
||||
.into_iter()
|
||||
let candidates: Vec<Endpoint> = get_local_addrs()?
|
||||
.map(|addr| SocketAddr::from((addr, device.listen_port.unwrap_or(51820))).into())
|
||||
.take(10)
|
||||
.collect::<Vec<Endpoint>>();
|
||||
log::info!(
|
||||
"reporting {} interface address{} as NAT traversal candidates...",
|
||||
|
@ -106,6 +106,8 @@ mod handlers {
|
||||
// This might be avoidable if we were able to run code after we were certain the response
|
||||
// had flushed over the TCP socket, but that isn't easily accessible from this high-level
|
||||
// web framework.
|
||||
//
|
||||
// Related: https://github.com/hyperium/hyper/issues/2181
|
||||
tokio::task::spawn(async move {
|
||||
tokio::time::sleep(*REDEEM_TRANSITION_WAIT).await;
|
||||
log::info!(
|
||||
|
@ -8,8 +8,8 @@ use parking_lot::{Mutex, RwLock};
|
||||
use rusqlite::Connection;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use shared::{
|
||||
AddCidrOpts, AddPeerOpts, DeleteCidrOpts, IoErrorContext, NetworkOpt, RenamePeerOpts,
|
||||
INNERNET_PUBKEY_HEADER,
|
||||
get_local_addrs, AddCidrOpts, AddPeerOpts, DeleteCidrOpts, Endpoint, IoErrorContext,
|
||||
NetworkOpt, PeerContents, RenamePeerOpts, INNERNET_PUBKEY_HEADER,
|
||||
};
|
||||
use std::{
|
||||
collections::{HashMap, VecDeque},
|
||||
@ -479,7 +479,7 @@ async fn serve(
|
||||
log::debug!("opening database connection...");
|
||||
let conn = open_database_connection(&interface, conf)?;
|
||||
|
||||
let peers = DatabasePeer::list(&conn)?;
|
||||
let mut peers = DatabasePeer::list(&conn)?;
|
||||
log::debug!("peers listed...");
|
||||
let peer_configs = peers
|
||||
.iter()
|
||||
@ -502,6 +502,27 @@ async fn serve(
|
||||
|
||||
log::info!("{} peers added to wireguard interface.", peers.len());
|
||||
|
||||
let candidates: Vec<Endpoint> = get_local_addrs()?
|
||||
.map(|addr| SocketAddr::from((addr, config.listen_port)).into())
|
||||
.collect();
|
||||
let num_candidates = candidates.len();
|
||||
let myself = peers
|
||||
.iter_mut()
|
||||
.find(|peer| peer.ip == config.address)
|
||||
.expect("Couldn't find server peer in peer list.");
|
||||
myself.update(
|
||||
&conn,
|
||||
PeerContents {
|
||||
candidates,
|
||||
..myself.contents.clone()
|
||||
},
|
||||
)?;
|
||||
|
||||
log::info!(
|
||||
"{} local candidates added to server peer config.",
|
||||
num_candidates
|
||||
);
|
||||
|
||||
let public_key = wgctrl::Key::from_base64(&config.private_key)?.generate_public();
|
||||
let db = Arc::new(Mutex::new(conn));
|
||||
let endpoints = spawn_endpoint_refresher(interface, network);
|
||||
|
@ -79,3 +79,31 @@ pub fn chmod(file: &File, new_mode: u32) -> Result<bool, io::Error> {
|
||||
|
||||
Ok(updated)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn _get_local_addrs() -> Result<impl Iterator<Item = std::net::IpAddr>, io::Error> {
|
||||
use nix::{net::if_::InterfaceFlags, sys::socket::SockAddr};
|
||||
|
||||
let addrs = nix::ifaddrs::getifaddrs()?
|
||||
.filter(|addr| {
|
||||
addr.flags.contains(InterfaceFlags::IFF_UP)
|
||||
&& !addr.flags.intersects(
|
||||
InterfaceFlags::IFF_LOOPBACK
|
||||
| InterfaceFlags::IFF_POINTOPOINT
|
||||
| InterfaceFlags::IFF_PROMISC,
|
||||
)
|
||||
})
|
||||
.filter_map(|addr| match addr.address {
|
||||
Some(SockAddr::Inet(addr)) if addr.to_std().is_ipv4() => Some(addr.to_std().ip()),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
Ok(addrs)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use netlink::get_local_addrs as _get_local_addrs;
|
||||
|
||||
pub fn get_local_addrs() -> Result<impl Iterator<Item = std::net::IpAddr>, io::Error> {
|
||||
Ok(_get_local_addrs()?.take(10))
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ fn get_links() -> Result<Vec<String>, io::Error> {
|
||||
Ok(links)
|
||||
}
|
||||
|
||||
pub fn get_local_addrs() -> Result<Vec<IpAddr>, io::Error> {
|
||||
pub fn get_local_addrs() -> Result<impl Iterator<Item = IpAddr>, io::Error> {
|
||||
let links = get_links()?;
|
||||
let addr_responses = netlink_call(
|
||||
RtnlMessage::GetAddress(AddressMessage::default()),
|
||||
@ -203,7 +203,7 @@ pub fn get_local_addrs() -> Result<Vec<IpAddr>, io::Error> {
|
||||
None
|
||||
})
|
||||
// Only select addresses for helpful links
|
||||
.filter(|nlas| nlas.iter().any(|nla| matches!(nla, address::nlas::Nla::Label(label) if links.contains(label))))
|
||||
.filter(move |nlas| nlas.iter().any(|nla| matches!(nla, address::nlas::Nla::Label(label) if links.contains(label))))
|
||||
.filter_map(|nlas| nlas.iter().find_map(|nla| match nla {
|
||||
address::nlas::Nla::Address(name) if name.len() == 4 => {
|
||||
let mut addr = [0u8; 4];
|
||||
@ -216,8 +216,7 @@ pub fn get_local_addrs() -> Result<Vec<IpAddr>, io::Error> {
|
||||
Some(IpAddr::V6(addr.into()))
|
||||
},
|
||||
_ => None,
|
||||
}))
|
||||
.collect::<Vec<_>>();
|
||||
}));
|
||||
Ok(addrs)
|
||||
}
|
||||
|
||||
@ -228,6 +227,6 @@ mod tests {
|
||||
#[test]
|
||||
fn test_local_addrs() {
|
||||
let addrs = get_local_addrs().unwrap();
|
||||
println!("{:?}", addrs);
|
||||
println!("{:?}", addrs.collect::<Vec<_>>());
|
||||
}
|
||||
}
|
||||
|
@ -166,31 +166,6 @@ pub fn add_route(interface: &InterfaceName, cidr: IpNetwork) -> Result<bool, io:
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use super::netlink::add_route;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn get_local_addrs() -> Result<Vec<IpAddr>, io::Error> {
|
||||
use nix::{net::if_::InterfaceFlags, sys::socket::SockAddr};
|
||||
|
||||
let addrs = nix::ifaddrs::getifaddrs()?
|
||||
.filter(|addr| {
|
||||
addr.flags.contains(InterfaceFlags::IFF_UP)
|
||||
&& !addr.flags.intersects(
|
||||
InterfaceFlags::IFF_LOOPBACK
|
||||
| InterfaceFlags::IFF_POINTOPOINT
|
||||
| InterfaceFlags::IFF_PROMISC,
|
||||
)
|
||||
})
|
||||
.filter_map(|addr| match addr.address {
|
||||
Some(SockAddr::Inet(addr)) if addr.to_std().is_ipv4() => Some(addr.to_std().ip()),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(addrs)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use super::netlink::get_local_addrs;
|
||||
|
||||
pub trait DeviceExt {
|
||||
/// Diff the output of a wgctrl device with a list of server-reported peers.
|
||||
fn diff<'a>(&'a self, peers: &'a [Peer]) -> Vec<PeerDiff<'a>>;
|
||||
|
Loading…
Reference in New Issue
Block a user