[bug] 当子网代理网段涵盖了中继服务器的IP时,将导致连接循环断开循环重连
- Dominant language
- Rust
- Stars
- 13.6k
- Forks
- 1.4k
- Avg merge
- 1d 9h
- Merged PRs (30d)
- 34
Description
### 问题简要描述 / Brief Description
例如,若节点A设置子网代理(如 1.2.3.0/24),且子网代理的网段涵盖了中继服务器C的IP地址(如 1.2.3.4),这将导致连接循环出错
### 环境信息 / Environment Information
**EasyTier 版本(非常重要)/ EasyTier Version (Very Important):** v2.6.4
**网络拓扑/ Network Topology:**
- 节点 A (100.254.14.1): Ubuntu 24.04.4 LTS (6.8.0-117-generic), 无 IPV6 地址,无公网 IPv4
- 节点B (100.254.14.2): Windows 11 Pro 22H2, 以太网,有 IPV6 地址,无公网 IPv4
- 节点 C (中继服务器): Ubuntu 24.04.4 LTS (6.8.0-117-generic), 无 IPV6 地址,无直接公网 IPv4(通过有公网IP的网关转发)
**中继服务器传输协议**:txt-wss
### 节点配置 / Node Configurations
```
[flags]
bind_device = true
lazy_p2p = true
proxy_forward_by_system = true
```
### 日志信息 / Log Information
一旦与B连接,A将不断抛出Connection timed out after 19.999s。中继服务器和B并不会产生特别的错误日志。
```
easytier-lab | 2026-08-05T13:09:10.676732327+08:00 INFO CORE::INSTANCE::CONNECTION: [57658d51-88c3-4f65-8080-a5dd340ef96d] new connection accepted local="ws://0.0.0.0:667/" remote="ws://10.131.231.0:37076/?proxy=127.0.0.1%3A37076"
easytier-lab | 2026-08-05T13:09:29.707134084+08:00 INFO CORE::INSTANCE::CONNECTION: [57658d51-88c3-4f65-8080-a5dd340ef96d] new connection accepted local="ws://0.0.0.0:667/" remote="ws://10.131.231.0:43082/?proxy=127.0.0.1%3A43082"
easytier-lab | 2026-08-05T13:10:17.295476811+08:00 INFO CORE::INSTANCE::CONNECTION: [57658d51-88c3-4f65-8080-a5dd340ef96d] new connection accepted local="ws://0.0.0.0:667/" remote="ws://****:46894/?proxy=127.0.0.1%3A46894"
```
```
2026-08-06T14:59:49.0948969+08:00 TRACE easytier::proto::rpc_impl::packet: got first piece rpc_packet=RpcPacket { from_peer: 1, to_peer: 1, transaction_id: -1311781887005041622, descriptor: Some(RpcDescriptor { domain_name: "", proto_name: "WebClientService", service_name: "WebClientService", method_index: 5 }), body: [24, 136, 39], is_request: true, total_pieces: 1, piece_idx: 0, trace_id: 0, compression_info: Some(RpcCompressionInfo { algo: None, accepted_algo: Zstd }) }
2026-08-06T14:59:49.0950843+08:00 TRACE easytier::proto::rpc_impl::bidirect: recv rpc packet from server packet=ZCPacket { inner: b"(\xb5/\xfd \x1f\xf9\0\0\x12\x1a\n\x18\x08\xd6\x91\xf7\xd9\x08\x10\x01\0\0\0\x01\0\0\0\t\0\x01 C\0\0\0\x08\x01\x10\x01\x18\xaa\xb8\x97\xd2\xae\xaa\xe7\xe5\xed\x01\"&\x12\x10WebClientService\x1a\x10WebClientService \x05*\x02\x18&8\x01R\x04\x08\x01\x10\x02", packet_type: NIC }
2026-08-06T14:59:49.0951548+08:00 TRACE easytier::proto::rpc_impl::client: Received response packet packet=RpcPacket { from_peer: 1, to_peer: 1, transaction_id: -1311781887005041622, descriptor: Some(RpcDescriptor { domain_name: "", proto_name: "WebClientService", service_name: "WebClientService", method_index: 5 }), body: [24, 38], is_request: false, total_pieces: 1, piece_idx: 0, trace_id: 0, compression_info: Some(RpcCompressionInfo { algo: None, accepted_algo: Zstd }) }
2026-08-06T14:59:49.0951787+08:00 TRACE easytier::proto::rpc_impl::packet: got first piece rpc_packet=RpcPacket { from_peer: 1, to_peer: 1, transaction_id: -1311781887005041622, descriptor: Some(RpcDescriptor { domain_name: "", proto_name: "WebClientService", service_name: "WebClientService", method_index: 5 }), body: [24, 38], is_request: false, total_pieces: 1, piece_idx: 0, trace_id: 0, compression_info: Some(RpcCompressionInfo { algo: None, accepted_algo: Zstd }) }
2026-08-06T14:59:50.106516+08:00 TRACE easytier::proto::rpc_impl::bidirect: recv rpc packet from client packet=ZCPacket { inner: b"(\xb5/\xfd \x1e\xf1\0\0\n\x1a\n\x18\x08\xd6\x91\xf7\xd9\x08\x10\x01\0\0\0\x01\0\0\0\x08\0\x01 8\0\0\0\x08\x01\x10\x01\x18\xab\xb8\x97\xd2\xae\xaa\xe7\xe5\xed\x01\"\x18\x12\tLoggerRpc\x1a\tLoggerRpc \x01*\x03\x18\x88'0\x018\x01R\x04\x08\x01\x10\x02", packet_type: NIC }
2026-08-06T14:59:50.1065923+08:00 TRACE easytier::proto::rpc_impl::server: Received request packet key=PacketMergerKey { from_peer_id: 1, transaction_id: -1311781887005041621 } packet=RpcPacket { from_peer: 1, to_peer: 1, transaction_id: -1311781887005041621, descriptor: Some(RpcDescriptor { domain_name: "", proto_name: "LoggerRpc", service_name: "LoggerRpc", method_index: 1 }), body: [24, 136, 39], is_request: true, total_pieces: 1, piece_idx: 0, trace_id: 0, compression_info: Some(RpcCompressionInfo { algo: None, accepted_algo: Zstd }) }
2026-08-06T14:59:50.1066196+08:00 TRACE easytier::proto::rpc_impl::packet: got first piece rpc_packet=RpcPacket { from_peer: 1, to_peer: 1, transaction_id: -1311781887005041621, descriptor: Some(RpcDescriptor { domain_name: "", proto_name: "LoggerRpc", service_name: "LoggerRpc", method_index: 1 }), body: [24, 136, 39], is_request: true, total_pieces: 1, piece_idx: 0, trace_id: 0, compression_info: Some(RpcCompressionInfo { algo: None, accepted_algo: Zstd }) }
2026-08-06T15:00:24.4819775+08:00 WARN easytier::connector::manual: conn_mgr_routine started
2026-08-06T15:00:25.7664914+08:00 ERROR easytier::tunnel::websocket: bind addr fail bind_addr=169.254.83.61:0 addr=***:443 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:00:25.8414472+08:00 ERROR easytier::tunnel::websocket: bind addr fail bind_addr=169.254.79.204:0 addr=***:443 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:00:25.9284413+08:00 ERROR easytier::tunnel::websocket: bind addr fail bind_addr=169.254.62.17:0 addr=***:443 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:00:26.0116477+08:00 ERROR easytier::tunnel::websocket: bind addr fail bind_addr=169.254.205.250:0 addr=***:443 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:00:26.0868886+08:00 ERROR easytier::tunnel::websocket: bind addr fail bind_addr=169.254.185.30:0 addr=***:443 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:00:26.639092+08:00 ERROR easytier::tunnel::websocket: bind addr fail bind_addr=169.254.203.236:0 addr=***:443 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:00:27.0422774+08:00 WARN easytier::peers::foreign_network_client: add new peer conn in foreign network client peer_conn=PeerConnInfo { conn_id: "e4af53d2-2132-4f58-a35c-0f176df0bbe7", my_peer_id: 3536306123, peer_id: 108277970, features: [], tunnel: Some(TunnelInfo { tunnel_type: "txt-wss", local_addr: Some(Url { url: "wss://172.20.8.2:50665/" }), remote_addr: Some(Url { url: "txt://****" }), resolved_remote_addr: Some(Url { url: "wss://***/" }) }), stats: Some(PeerConnStats { rx_bytes: 72, tx_bytes: 95, rx_packets: 1, tx_packets: 1, latency_us: 0 }), loss_rate: 0.0, is_client: true, network_name: "default", is_closed: false, noise_local_static_pubkey: [], noise_remote_static_pubkey: [], secure_auth_level: None, peer_identity_type: Admin } network=NetworkIdentity { network_name: "default", network_secret: None, network_secret_digest: Some([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) }
2026-08-06T15:00:27.0427333+08:00 WARN easytier::peers::peer_ospf_route: new_initiator: Some(108277970), prev: None, my_id: 3536306123
2026-08-06T15:00:27.0429757+08:00 WARN easytier::connector::manual: reconn_tasks done, reconn result: Some(Ok(ReconnResult { dead_url: "txt://****", peer_id: 108277970, conn_id: e4af53d2-2132-4f58-a35c-0f176df0bbe7 }))
2026-08-06T15:00:27.0429881+08:00 WARN easytier::peers::peer_ospf_route: session id mismatch, clear saved info. self=SyncRouteSession { my_peer_id: 3536306123, dst_peer_id: 108277970, dst_saved_peer_info_versions: {}, dst_saved_conn_info_version: {}, dst_saved_foreign_network_versions: {}, unreachable_peers_for_peer_info: Mutex { data: {} }, unreachable_peers_for_conn_info: Mutex { data: {} }, last_sync_succ_timestamp: AtomicCell { value: None }, my_session_id: 4721587408073801249, dst_session_id: 0, we_are_initiator: true, dst_is_initiator: false, need_sync_initiator_info: false, rpc_tx_count: 0, rpc_rx_count: 1, task: SessionTask { is_running: true }, lock: Mutex { data: } } session_id=1374384496456871932
2026-08-06T15:00:30.5574529+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.83.61:0 addr=***:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:00:30.690743+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.79.204:0 addr=***:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:00:30.7872338+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.62.17:0 addr=***:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:00:30.9204355+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.205.250:0 addr=***:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:00:31.0389135+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.185.30:0 addr=***:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:00:33.4442869+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.203.236:0 addr=***:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:00:56.662394+08:00 WARN easytier::peers::peer: notified that peer conn is closed peer_node_id=108277970 ret=e4af53d2-2132-4f58-a35c-0f176df0bbe7
2026-08-06T15:00:56.6651289+08:00 WARN easytier::peers::peer_ospf_route: stop ospf sync session peer_id=108277970
2026-08-06T15:00:56.6651791+08:00 ERROR easytier::peers::peer_ospf_route: sync_route_info failed ret=Err(Timeout(Elapsed(()))) my_peer_id=3536306123 dst_peer_id=108277970 e=Timeout(Elapsed(()))
2026-08-06T15:00:56.6661258+08:00 WARN easytier::connector::udp_hole_punch::common: creating udp hole punching listener max_listeners=4
2026-08-06T15:00:56.6675208+08:00 WARN easytier::connector::udp_hole_punch::common: creating udp hole punching listener max_listeners=4
2026-08-06T15:00:56.6687681+08:00 ERROR easytier::peers::peer_manager: forward packet error ret=Err(RouteError(None)) to_peer_id=4015002056 from_peer_id=3536306123
2026-08-06T15:00:56.6688058+08:00 ERROR easytier::peers::peer_manager: forward packet error ret=Err(RouteError(None)) to_peer_id=4015002056 from_peer_id=3536306123
2026-08-06T15:00:56.6688172+08:00 ERROR easytier::peers::peer_manager: forward packet error ret=Err(RouteError(None)) to_peer_id=3550962079 from_peer_id=3536306123
2026-08-06T15:00:56.6688258+08:00 ERROR easytier::peers::peer_manager: forward packet error ret=Err(RouteError(None)) to_peer_id=4015002056 from_peer_id=3536306123
2026-08-06T15:00:56.6688342+08:00 ERROR easytier::peers::peer_manager: forward packet error ret=Err(RouteError(None)) to_peer_id=3550962079 from_peer_id=3536306123
2026-08-06T15:00:57.3950141+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.83.61:0 addr=192.168.211.2:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:00:57.5477125+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.79.204:0 addr=192.168.211.2:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:00:57.6949803+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.62.17:0 addr=192.168.211.2:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:00:57.806771+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.205.250:0 addr=192.168.211.2:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:00:57.9551605+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.185.30:0 addr=192.168.211.2:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:00.2185712+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.203.236:0 addr=192.168.211.2:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:00.5131221+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.83.61:0 addr=100.70.0.1:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:00.7704111+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.79.204:0 addr=100.70.0.1:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:00.9230764+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.62.17:0 addr=100.70.0.1:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:01.080171+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.205.250:0 addr=100.70.0.1:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:01.2542144+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.185.30:0 addr=100.70.0.1:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:01.373198+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.83.61:0 addr=100.100.100.101:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:01.4962003+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.79.204:0 addr=100.100.100.101:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:01.7544165+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.62.17:0 addr=100.100.100.101:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:02.1220317+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.205.250:0 addr=100.100.100.101:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:02.4048083+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.185.30:0 addr=100.100.100.101:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:02.7968561+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.203.236:0 addr=100.70.0.1:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:03.3318869+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.203.236:0 addr=100.100.100.101:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:03.5507655+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.83.61:0 addr=10.131.231.0:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:03.6410785+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.79.204:0 addr=10.131.231.0:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:03.7569257+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.62.17:0 addr=10.131.231.0:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:03.8643295+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.205.250:0 addr=10.131.231.0:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:04.0433876+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.83.61:0 addr=192.168.255.3:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:04.0671076+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.185.30:0 addr=10.131.231.0:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
2026-08-06T15:01:04.169292+08:00 ERROR easytier::tunnel::tcp: bind addr fail bind_addr=169.254.79.204:0 addr=192.168.255.3:11010 error=IOError(Os { code: 10049, kind: AddrNotAvailable, message: "在其上下文中,该请求的地址无效。" })
```
### 重现步骤 / Reproduction Steps
注意:需要A B之间从未打洞成功过,否则无法复现
0. 节点A设置子网代理(如 1.2.3.0/24),但中继服务器C的IP地址在此子网内(如 1.2.3.4)
1. 客户端B上线
2. 客户端连接到中继服务器C
3. 节点A上线
4. 客户端试图连接节点A
5. 由于节点A下发了子网代理(如 1.2.3.0/24),**导致1.2.3.4走easytier tun**,使得中继服务器C失联
6. 与中继服务器C、节点A断开连接,子网代理设置自动清除
7. 子网代理设置自动清除,因此可以重新与C连接,然后循环步骤3-7
### 预期结果 / Expected Behavior
当下发的子网代理涵盖了中继服务器的IP时,需要隐含为子网代理创建一个单独的/32路由明确中继服务器的流量目的地不得是Easytier TUN,防止环路。这也是目前wireguard等VPN在设置0.0.0.0/0代理时的通用做法,例如自动执行:
```
ip route add 1.2.3.4/32 via 1.2.3.1 dev eth0
```
### 额外信息 / Additional Context
_No response_
Contributor guide
Research direction
Reproduce the failure with the reported subnet-proxy configuration and trace the connection lifecycle through the logged easytier::connector, easytier::tunnel, and easytier::peers modules. Compare the reconnects, bind failures, and route timeouts when the proxy subnet contains the relay IP; done means the connection remains stable without repeated timeout and reconnect cycles.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 45/100