Skip to content

Commit

Permalink
fix: show all listening addrs
Browse files Browse the repository at this point in the history
  • Loading branch information
dignifiedquire committed May 3, 2023
1 parent 7717243 commit b84ed59
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 45 deletions.
50 changes: 37 additions & 13 deletions src/hp/magicsock/conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,13 +324,16 @@ impl Conn {
Ok(res)
}

pub async fn local_addr(&self) -> Result<SocketAddr> {
pub async fn local_addr(&self) -> Result<(SocketAddr, Option<SocketAddr>)> {
let (s, r) = sync::oneshot::channel();
self.actor_sender
.send_async(ActorMessage::GetLocalAddr(s))
.await?;
let res = r.await??;
Ok(res)
let (v4, v6) = r.await?;
if let Some(v6) = v6 {
return Ok((v4?, Some(v6?)));
}
Ok((v4?, None))
}

/// Triggers an address discovery. The provided why string is for debug logging only.
Expand Down Expand Up @@ -663,9 +666,13 @@ impl AsyncUdpSocket for Conn {
self.actor_sender
.send(ActorMessage::GetLocalAddr(s))
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
let res = tokio::task::block_in_place(|| r.blocking_recv())
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))??;
Ok(res)
let (v4, v6) = tokio::task::block_in_place(|| r.blocking_recv())
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
// Default to v6 to pretend v6 for quinn in all cases (needs more thought)
if let Some(v6) = v6 {
return v6;
}
v4
}
}

Expand Down Expand Up @@ -715,7 +722,7 @@ impl Drop for WgGuard {

#[derive(Debug)]
pub(super) enum ActorMessage {
GetLocalAddr(sync::oneshot::Sender<io::Result<SocketAddr>>),
GetLocalAddr(sync::oneshot::Sender<(io::Result<SocketAddr>, Option<io::Result<SocketAddr>>)>),
SetDerpMap(Option<DerpMap>, sync::oneshot::Sender<()>),
GetDerpRegion(usize, sync::oneshot::Sender<Option<DerpRegion>>),
TrackedEndpoints(sync::oneshot::Sender<Vec<key::node::PublicKey>>),
Expand Down Expand Up @@ -1063,7 +1070,11 @@ impl Actor {
}

// Normalize local_ip
meta.dst_ip = self.local_addr().await.ok().map(|addr| addr.ip());
meta.dst_ip = self
.normalized_local_addr()
.await
.ok()
.map(|addr| addr.ip());

// ep.noteRecvActivity();
// if stats := c.stats.Load(); stats != nil {
Expand All @@ -1074,15 +1085,24 @@ impl Actor {

true
}
async fn normalized_local_addr(&self) -> io::Result<SocketAddr> {
let (v4, v6) = self.local_addr().await;
if let Some(v6) = v6 {
return v6;
}
v4
}

async fn local_addr(&self) -> io::Result<SocketAddr> {
async fn local_addr(&self) -> (io::Result<SocketAddr>, Option<io::Result<SocketAddr>>) {
// TODO: think more about this
// needs to pretend ipv6 always as the fake addrs are ipv6
let mut ipv6_addr = None;
if let Some(ref conn) = self.pconn6 {
return conn.local_addr().await;
ipv6_addr = Some(conn.local_addr().await);
}
let addr = self.pconn4.local_addr().await?;
Ok(addr)
let ipv4_addr = self.pconn4.local_addr().await;

(ipv4_addr, ipv6_addr)
}

async fn on_stun_receive(&self, packet: &[u8], addr: SocketAddr) {
Expand Down Expand Up @@ -1125,7 +1145,11 @@ impl Actor {
stride: dm.buf.len(),
addr: ep_fake_wg_addr,
// Normalize local_ip
dst_ip: self.local_addr().await.ok().map(|addr| addr.ip()),
dst_ip: self
.normalized_local_addr()
.await
.ok()
.map(|addr| addr.ip()),
ecn: None,
};

Expand Down
8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ mod tests {
provider.auth_token(),
expect_hash.into(),
expect_name.clone(),
provider.local_address().await.unwrap(),
provider.local_address().await.unwrap()[0],
provider.peer_id(),
content.to_vec(),
)));
Expand Down Expand Up @@ -409,7 +409,7 @@ mod tests {
hash,
auth_token,
get::Options {
addr: provider_addr,
addr: provider_addr[0],
peer_id: None,
keylog: true,
},
Expand Down Expand Up @@ -459,7 +459,7 @@ mod tests {
hash,
auth_token,
get::Options {
addr: provider_addr,
addr: provider_addr[0],
peer_id: None,
keylog: true,
},
Expand Down Expand Up @@ -507,7 +507,7 @@ mod tests {
hash,
auth_token,
get::Options {
addr,
addr: addr[0],
peer_id,
keylog: true,
},
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ async fn main_impl() -> Result<()> {
let client = make_rpc_client(rpc_port).await?;
let response = client.rpc(IdRequest).await?;

println!("Listening address: {}", response.listen_addr);
println!("Listening address: {:#?}", response.listen_addrs);
println!("PeerID: {}", response.peer_id);
println!("Auth token: {}", response.auth_token);
Ok(())
Expand Down Expand Up @@ -696,7 +696,7 @@ async fn provide(
builder.keypair(keypair).spawn().await?
};

println!("Listening address: {}", provider.local_address().await?);
println!("Listening address: {:#?}", provider.local_address().await?);
println!("PeerID: {}", provider.peer_id());
println!("Auth token: {}", provider.auth_token());
println!();
Expand Down
65 changes: 46 additions & 19 deletions src/net/ip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use std::net::{IpAddr, Ipv6Addr, SocketAddr};

use anyhow::{ensure, Result};
use tracing::debug;

const IFF_UP: u32 = 0x1;
const IFF_LOOPBACK: u32 = 0x8;
Expand Down Expand Up @@ -152,28 +153,54 @@ pub const fn is_unicast_link_local(addr: Ipv6Addr) -> bool {
}

/// Given a listen/bind address, finds all the local addresses for that address family.
pub(crate) fn find_local_addresses(listen_addr: SocketAddr) -> Result<Vec<SocketAddr>> {
let listen_ip = listen_addr.ip();
let listen_port = listen_addr.port();
let addrs: Vec<SocketAddr> = match listen_ip.is_unspecified() {
true => {
pub(crate) fn find_local_addresses(listen_addrs: &[SocketAddr]) -> Result<Vec<SocketAddr>> {
debug!("find_local_address: {:?}", listen_addrs);

let mut addrs = Vec::new();
let mut local_addrs = None;

for addr in listen_addrs {
if addr.ip().is_unspecified() {
// Find all the local addresses for this address family.
let addrs = LocalAddresses::new();
addrs
.regular
.iter()
.filter(|addr| match addr {
IpAddr::V4(_) if listen_ip.is_ipv4() => true,
IpAddr::V6(_) if listen_ip.is_ipv6() => true,
_ => false,
})
.copied()
.map(|addr| SocketAddr::from((addr, listen_port)))
.collect()
if local_addrs.is_none() {
local_addrs = Some(LocalAddresses::new());
debug!("found local addresses: {:?}", local_addrs);
}
let local_addrs = local_addrs.as_ref().unwrap();
let port = addr.port();

match addr.ip() {
IpAddr::V4(_) => {
addrs.extend(
local_addrs
.regular
.iter()
.chain(local_addrs.loopback.iter())
.filter(|a| a.is_ipv4())
.map(|a| SocketAddr::new(*a, port)),
);
}
IpAddr::V6(_) => {
addrs.extend(
local_addrs
.regular
.iter()
.chain(local_addrs.loopback.iter())
.filter(|a| a.is_ipv6())
.map(|a| SocketAddr::new(*a, port)),
);
}
}
} else {
addrs.push(*addr);
}
false => vec![listen_addr],
};
}
// we might have added duplicates, make sure to remove them
addrs.sort();
addrs.dedup();

ensure!(!addrs.is_empty(), "No local addresses found");

Ok(addrs)
}

Expand Down
25 changes: 19 additions & 6 deletions src/provider/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,15 +398,15 @@ impl Provider {
/// Note that this could be an unspecified address, if you need an address on which you
/// can contact the provider consider using [`Provider::listen_addresses`]. However the
/// port will always be the concrete port.
pub async fn local_address(&self) -> Result<SocketAddr> {
self.inner.conn.local_addr().await
pub async fn local_address(&self) -> Result<Vec<SocketAddr>> {
self.inner.local_address().await
}

/// Returns all addresses on which the provider is reachable.
///
/// This will never be empty.
pub async fn listen_addresses(&self) -> Result<Vec<SocketAddr>> {
find_local_addresses(self.local_address().await?)
self.inner.listen_addresses().await
}

/// Returns the [`PeerId`] of the provider.
Expand Down Expand Up @@ -458,6 +458,20 @@ impl Provider {
}
}

impl ProviderInner {
async fn local_address(&self) -> Result<Vec<SocketAddr>> {
let (v4, v6) = self.conn.local_addr().await?;
let mut addrs = vec![v4];
if let Some(v6) = v6 {
addrs.push(v6);
}
Ok(addrs)
}
async fn listen_addresses(&self) -> Result<Vec<SocketAddr>> {
find_local_addresses(&self.local_address().await?)
}
}

/// The future completes when the spawned tokio task finishes.
impl Future for Provider {
type Output = Result<(), Arc<JoinError>>;
Expand Down Expand Up @@ -560,14 +574,13 @@ impl RpcHandler {
IdResponse {
peer_id: Box::new(self.inner.keypair.public().into()),
auth_token: Box::new(self.inner.auth_token),
listen_addr: Box::new(self.inner.conn.local_addr().await.unwrap()),
listen_addrs: self.inner.listen_addresses().await.unwrap_or_default(),
version: env!("CARGO_PKG_VERSION").to_string(),
}
}
async fn addrs(self, _: AddrsRequest) -> AddrsResponse {
AddrsResponse {
addrs: find_local_addresses(self.inner.conn.local_addr().await.unwrap())
.unwrap_or_default(),
addrs: self.inner.listen_addresses().await.unwrap_or_default(),
}
}
async fn shutdown(self, request: ShutdownRequest) {
Expand Down
2 changes: 1 addition & 1 deletion src/rpc_protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ pub struct WatchResponse {
pub struct IdResponse {
pub peer_id: Box<PeerId>,
pub auth_token: Box<AuthToken>,
pub listen_addr: Box<SocketAddr>,
pub listen_addrs: Vec<SocketAddr>,
pub version: String,
}

Expand Down

0 comments on commit b84ed59

Please sign in to comment.