Skip to content

try to get public address via igd#2166

Open
cfdworld wants to merge 3 commits intoEasyTier:mainfrom
cfdworld:upnp-igd
Open

try to get public address via igd#2166
cfdworld wants to merge 3 commits intoEasyTier:mainfrom
cfdworld:upnp-igd

Conversation

@cfdworld
Copy link
Copy Markdown
Contributor

尝试优先通过igd获得easytier所在主机的网关地址用于建立p2p连接。此pr后,可以支持同一公网内两台路由器(这两台路由器需要可以互访)下的两个easytier主机通过两个网关地址建立p2p连接。此pr会影响公网地址获得,影响原来的功能,可能需要加一个选项来设置是否开启。由于对rust并不熟悉,仅抛砖引玉,看大佬是否可以帮忙完善。

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR changes UDP public address resolution to prefer deriving the public IP via UPnP/IGD (and combine it with the mapped external port) to improve P2P connectivity in certain multi-router / same-public-network scenarios.

Changes:

  • Added try_get_public_addr_via_upnp to obtain external IP from an IGD gateway and build a public SocketAddr.
  • Updated resolve_udp_public_addr to attempt IGD-based public address resolution and fall back to STUN on failure.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread easytier/src/common/upnp.rs Outdated
Comment on lines +268 to +276
match try_get_public_addr_via_upnp(&global_ctx, local_listener, &port_mapping).await {
Ok(public_addr) => {
tracing::info!(%local_listener, %public_addr, "got public addr via upnp/igd");
mapped_addr = public_addr;
}
Err(err) => {
tracing::debug!(?err, "upnp/igd failed, fallback to stun");
}
}
Comment thread easytier/src/common/upnp.rs Outdated
Comment on lines +229 to +241
let (gateway, _local_addr) = ActiveUdpPortMapping::discover_igd_gateway(global_ctx, local_listener).await?;

let public_ip = gateway.get_external_ip().await
.context("failed to get external ip from gateway")?;

let lease_ref = mapping.as_ref();

let public_addr = if let Some(lease) = lease_ref {
SocketAddr::new(public_ip, lease.gateway_external_port())
} else {
bail!("port mapping lease is required to get external port")
};
Ok(public_addr)
Comment thread easytier/src/common/upnp.rs Outdated
Comment on lines +229 to +240
let (gateway, _local_addr) = ActiveUdpPortMapping::discover_igd_gateway(global_ctx, local_listener).await?;

let public_ip = gateway.get_external_ip().await
.context("failed to get external ip from gateway")?;

let lease_ref = mapping.as_ref();

let public_addr = if let Some(lease) = lease_ref {
SocketAddr::new(public_ip, lease.gateway_external_port())
} else {
bail!("port mapping lease is required to get external port")
};
Comment thread easytier/src/common/upnp.rs Outdated
Comment on lines +229 to +241
let (gateway, _local_addr) = ActiveUdpPortMapping::discover_igd_gateway(global_ctx, local_listener).await?;

let public_ip = gateway.get_external_ip().await
.context("failed to get external ip from gateway")?;

let lease_ref = mapping.as_ref();

let public_addr = if let Some(lease) = lease_ref {
SocketAddr::new(public_ip, lease.gateway_external_port())
} else {
bail!("port mapping lease is required to get external port")
};
Ok(public_addr)
Comment on lines +268 to +275
match try_get_public_addr_via_upnp(&global_ctx, local_listener, &port_mapping).await {
Ok(public_addr) => {
tracing::info!(%local_listener, %public_addr, "got public addr via upnp/igd");
mapped_addr = public_addr;
}
Err(err) => {
tracing::debug!(?err, "upnp/igd failed, fallback to stun");
}
Comment on lines +268 to +272
match try_get_public_addr_via_upnp(&global_ctx, local_listener, &port_mapping).await {
Ok(public_addr) => {
tracing::info!(%local_listener, %public_addr, "got public addr via upnp/igd");
mapped_addr = public_addr;
}
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@KKRainbow
Copy link
Copy Markdown
Member

我感觉 stun 取 public ip 已经非常成熟稳定了,改用 igd 好像收益有限

@cfdworld
Copy link
Copy Markdown
Contributor Author

cfdworld commented May 1, 2026

我感觉 stun 取 public ip 已经非常成熟稳定了,改用 igd 好像收益有限

感谢大佬。如果easytier所在主机的网关(简称网关A)具有公网ip地址,那么使用stun或者igd两种方法一致,应该获得相同的“公网地址”。然而,如果网关A不具有公网地址,此时stun获得的应该是网关A上层网关(可能有多层nat)的公网地址,但igd方法获得的是网关A的地址(可能是私网地址)。因此,两种实现获得的ip地址是由一定区别的。

这个pr主要是提供一个方案。供同一内网(比如典型的校园网,有同一公网地址)下的两个网关(网关A,网关B)下的两台主机(主机C,主机D)能直接建立p2p连接。拓扑关系描述如下:主机C在网关A下,主机D在网关B下,网关A和网关B可以通过各自的ip地址通信。由于网关A和B均进行了nat,此时主机C和D没有办法直接p2p。启用此pr后,主机C上的easytier使用igd协议建立端口映射,主机D上的easytier通过网关A的ip地址可直接与主机C上的easytier进行p2p。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants