EasyTier / EasyTier/EasyTier

[bug] 当子网代理网段涵盖了中继服务器的IP时,将导致连接循环断开循环重连

Open
#2,474 3 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.