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

nathole: upnp support #4110

Closed
wants to merge 1 commit into from

Conversation

slayercat
Copy link

WHY

When a router supports UPnP, frpc can be configured to utilize the UPnP protocol to assist with tunnel traversal.

This method can circumvent issues associated with the lack of support for STUN, enhancing the possibility of establishing direct connections.

It is important to note that UPnP operates as a plaintext protocol. Therefore, it should be disabled in scenarios where secure, concealed communication is required.

By default, this configuration is disabled, and it requires the specification of the program name to be exposed to UPnP devices.

see also:

#1823
#3703

@fatedier
Copy link
Owner

Thanks for your contribution.

However, for such functionality, we need to be more cautious in our design and thinking. We usually do not tend to directly submit code, but rather submit proposals and specific implementation paths in the issue, discuss and reach a consensus before attempting to code, in order to avoid wasting valuable time due to inconsistencies with project planning.

There has been no progress on this issue for various reasons. One reason is that I am not clear on how useful this functionality is in the current network environment. This capability may require testing and long-term maintenance in various network environments, which would increase the project's maintenance costs. We should only consider it when the benefits are clearly greater than the added costs. Additionally, during the transition period of major version refactoring, we hope to minimize the complexity brought by new features.

@slayercat
Copy link
Author

slayercat commented Mar 28, 2024

Thank you very much for your prompt and timely response. I understand and agree with your concerns.

With the development of technologies such as P2P, initiating UPnP requests and asking routers to cooperate is a common technique in scenarios requiring public network mapping. Investigation and testing in this context, as outlined in #1823, demonstrate that even within ISP-level NAT networks, some providers offer support for related technologies.

In IPv6 environments, even though each endpoint can acquire an IPv6 address, most routers currently block all inbound requests from the internet for security reasons. Therefore, it's still necessary to configure the opening of corresponding ports. The use of UPnP in these scenarios retains significant value.

Moreover, some tools also offer similar functionalities, like ZeroTier (https://www.zerotier.com/).

The current implementation is a straightforward extension of the STUN implementation for xTCP.

After acquiring a public IP address, a callback is invoked. If permitted by the configuration, the UPnP feature is used to direct the router to transfer the externally exposed port to an open UDP port, thereby "creating" an EasyNAT in this environment. The subsequent process fully reuses the STUN procedure.

I haven't closely examined the current implementation, but my assumption is that either the visitor or the proxy needs to be reachable by the other party for a direct connection to be established without the need for server relay. Therefore, I have implemented related configuration code on both the visitor and the proxy sides.

If there's any misunderstanding on my part, please kindly correct me.

Below is a log output from a proxy with this feature enabled, for your reference.

�[0m�[1;34m2024-03-28 16:00:47.664 [I] [upnp/upnp.go:152] [eb610f92188d954b] [xtcpname] UPNP_ForwardPort: remoteAddrPort=221.2xx.xx.187:50475, localAddrPort=0.0.0.0:50475, targetForwardToLocal=192.xxx.1.xx
�[0m�[1;34m2024-03-28 16:00:49.844 [I] [proxy/xtcp.go:90] [eb610f92188d954b] [xtcpname] nathole prepare success, nat type: EasyNAT, behavior: BehaviorNoChange, addresses: [221.2xx.xx.187:50475 221.2xx.xx.187:50475], assistedAddresses: [192.xxx.1.xx:50475]
�[0m�[1;34m2024-03-28 16:00:49.876 [I] [proxy/xtcp.go:111] [eb610f92188d954b] [xtcpname] get natHoleRespMsg, sid [1711612847ba5bde1eba9b27da], protocol [quic], candidate address [222.1xx.xx.114:65073 222.xxx.xx.124:65073], assisted address [10.250.xx.xxx:65073 192.168.168.1:65073 192.168.88.1:65073 172.24.96.1:65073], detectBehavior: {Role:receiver Mode:1 TTL:7 SendDelayMs:0 ReadTimeoutMs:5000 CandidatePorts:[{From:65068 To:65078}] SendRandomPorts:0 ListenRandomPorts:0}
�[0m�[1;34m2024-03-28 16:00:50.888 [I] [proxy/xtcp.go:127] [eb610f92188d954b] [xtcpname] establishing nat hole connection successful, sid [1711612847ba5bde1eba9b27da], remoteAddr [222.xxx.xx.34:65073]
�[0m�[1;34m2024-03-28 17:53:49.946 [I] [upnp/upnp.go:152] [eb610f92188d954b] [xtcpname] UPNP_ForwardPort: remoteAddrPort=221.2xx.xx.187:65531, localAddrPort=0.0.0.0:65531, targetForwardToLocal=192.xxx.1.xx
�[0m�[1;34m2024-03-28 17:53:52.114 [I] [proxy/xtcp.go:90] [eb610f92188d954b] [xtcpname] nathole prepare success, nat type: EasyNAT, behavior: BehaviorNoChange, addresses: [221.2xx.xx.187:65531 221.2xx.xx.187:65531], assistedAddresses: [192.xxx.1.xx:65531]
�[0m�[1;34m2024-03-28 17:53:53.175 [I] [proxy/xtcp.go:111] [eb610f92188d954b] [xtcpname] get natHoleRespMsg, sid [171161963005e62677a9428fa2], protocol [quic], candidate address [222.xxx.xx.124:56098 222.xxx.xx.34:56098], assisted address [10.250.xx.xxx:56098 192.168.168.1:56098 192.168.88.1:56098 172.24.96.1:56098], detectBehavior: {Role:sender Mode:2 TTL:0 SendDelayMs:3000 ReadTimeoutMs:35000 CandidatePorts:[] SendRandomPorts:1000 ListenRandomPorts:0}
�[0m�[1;34m2024-03-28 17:53:57.434 [I] [proxy/xtcp.go:127] [eb610f92188d954b] [xtcpname] establishing nat hole connection successful, sid [171161963005e62677a9428fa2], remoteAddr [222.xxx.xx.34:64423]

@fatedier
Copy link
Owner

I suggest creating a new issue to track this proposal, and it may be necessary to pay attention to the following points:

  1. The implementation methods and configuration options in other similar projects, such as the ZeroTier you mentioned above. We should try to draw on the solutions of mature projects as much as possible.
  2. Seek some early users to help test and verify in which scenarios the solution can indeed solve the problem.
  3. What side effects might there be, and how to avoid them.

Copy link

PRs go stale after 21d of inactivity. Stale PRs rot after an additional 7d of inactivity and eventually close.

@wuai1024
Copy link

我非常需要这个,有环境可以测试下这个,请问要如何使用这个代码,进行编译测试。

@slayercat
Copy link
Author

我非常需要这个,有环境可以测试下这个,请问要如何使用这个代码,进行编译测试。

代码在这里:https://github.com/slayercat/frp/tree/dev-nathole-upnp-helpers

git clone git@github.com:slayercat/frp.git

cd frp

git checkout origin/dev-nathole-upnp-helpers

剩下的流程与正常构建一致。

@wuai1024
Copy link

我非常需要这个,有环境可以测试下这个,请问要如何使用这个代码,进行编译测试。

代码在这里:https://github.com/slayercat/frp/tree/dev-nathole-upnp-helpers

git clone git@github.com:slayercat/frp.git

cd frp

git checkout origin/dev-nathole-upnp-helpers

剩下的流程与正常构建一致。

测试后,frpc to xtcp 代理端日志:

2024-06-17 16:42:36.368 [I] [proxy/xtcp.go:90] [efbb49835709a4d9] [ikuai.ssh] nathole prepare success, nat type: EasyNAT, behavior: BehaviorNoChange, addresses: [x.x.x.x:8224 x.x.x.x:8224], assistedAddresses: [192.168.253.5:41411]
2024-06-17 16:42:37.378 [I] [proxy/xtcp.go:111] [efbb49835709a4d9] [ikuai.ssh] get natHoleRespMsg, sid [1718613755e740b3bdc4976603], protocol [quic], candidate address [y.y.y.y:24478 y.y.y.y:24478], assisted address [192.168.6.180:56382 192.168.64.1:56382], detectBehavior: {Role:sender Mode:2 TTL:0 SendDelayMs:3000 ReadTimeoutMs:35000 CandidatePorts:[] SendRandomPorts:1000 ListenRandomPorts:0}
2024-06-17 16:43:15.380 [W] [proxy/xtcp.go:119] [efbb49835709a4d9] [ikuai.ssh] make hole error: wait detect message error: read udp4 0.0.0.0:41411: i/o timeout
2024-06-17 16:44:44.147 [I] [proxy/xtcp.go:90] [efbb49835709a4d9] [ikuai.ssh] nathole prepare success, nat type: EasyNAT, behavior: BehaviorNoChange, addresses: [x.x.x.x:8384 x.x.x.x:8384], assistedAddresses: [192.168.253.5:40358]
2024-06-17 16:44:45.156 [I] [proxy/xtcp.go:111] [efbb49835709a4d9] [ikuai.ssh] get natHoleRespMsg, sid [1718613883e34c169b73460e78], protocol [quic], candidate address [y.y.y.y:3977 y.y.y.y:3977], assisted address [192.168.6.180:51182 192.168.64.1:51182], detectBehavior: {Role:sender Mode:2 TTL:0 SendDelayMs:3000 ReadTimeoutMs:35000 CandidatePorts:[] SendRandomPorts:1000 ListenRandomPorts:0}
2024-06-17 16:45:23.158 [W] [proxy/xtcp.go:119] [efbb49835709a4d9] [ikuai.ssh] make hole error: wait detect message error: read udp4 0.0.0.0:40358: i/o timeout

没有发起upnp连接。

image

测试镜像使用上述代码编译后运行:

docker pull qq851161583/frpc:upnp

@wuai1024
Copy link

看日志是 NAT 类型检测成功了,然后打洞后,未成功将端口上报给 路由器 的 upnp,导致连接失败。

@wuai1024
Copy link

最新进展,根据 pr内容中的配置文件,添加后,运行得到如下日志:

2024-06-17 17:08:30.749 [I] [upnp/upnp.go:152] [2af55021c903f4e5] [ikuai.ssh] UPNP_ForwardPort: remoteAddrPort=x.x.x.x:8329, localAddrPort=0.0.0.0:48424, targetForwardToLocal=192.168.253.5
2024-06-17 17:08:32.750 [W] [upnp/upnp.go:166] [2af55021c903f4e5] [ikuai.ssh] UPNP_ForwardPort error: multiple or no services found.
2024-06-17 17:08:32.750 [I] [proxy/xtcp.go:90] [2af55021c903f4e5] [ikuai.ssh] nathole prepare success, nat type: EasyNAT, behavior: BehaviorNoChange, addresses: [x.x.x.x:8329 x.x.x.x:8329], assistedAddresses: [192.168.253.5:48424]
2024-06-17 17:08:32.757 [I] [proxy/xtcp.go:111] [2af55021c903f4e5] [ikuai.ssh] get natHoleRespMsg, sid [1718615309c7d30d6f39fc7910], protocol [quic], candidate address [y.y.y.y:30657 y.y.y.y:30657], assisted address [192.168.6.180:65366 192.168.64.1:65366], detectBehavior: {Role:receiver Mode:1 TTL:4 SendDelayMs:0 ReadTimeoutMs:5000 CandidatePorts:[{From:30652 To:30662}] SendRandomPorts:0 ListenRandomPorts:0}
2024-06-17 17:08:37.810 [W] [proxy/xtcp.go:119] [2af55021c903f4e5] [ikuai.ssh] make hole error: wait detect message error: read udp4 0.0.0.0:48424: i/o timeout

看起来应该没什么问题了,这个获取不到upnp服务器的问题,可能是因为我的服务部署在docker内跨网段了,我调整下后再测试下。

@slayercat
Copy link
Author

感谢测试。upnp服务器这个,建议检查一下网段问题或相关路由器是否开启

@wuai1024
Copy link

感谢测试。upnp服务器这个,建议检查一下网段问题或相关路由器是否开启

嗯,这个我的网络环境比较复杂,目前网络被旁路由接管了,出口路由docker部署了直接dmz的。upnp跨网段了,我后面再简化下了测试下。感谢对这个功能的付出。希望 upnp 能早日转正。

@wuai1024
Copy link

我又测试了下,网络环境里是有 upnp 服务器的,就是我的 路由器。 启动后,还是显示 找不到

UPNP_ForwardPort error: multiple or no services found.

@wuai1024
Copy link

image

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

Successfully merging this pull request may close these issues.

3 participants