Skip to content

Commit f64bd53

Browse files
committed
```
feat(network): 更新FakeIP策略为环形缓冲区并支持gethostbyname拦截 - 将FakeIP地址范围从10.0.0.0/8改为198.18.0.0/15(基准测试保留网段) - 实现环形缓冲区策略替代原有无限增长映射表,自动循环复用地址池 - 添加对gethostbyname函数的Hook支持,增强DNS拦截能力 - 移除max_entries配置项,采用固定容量的循环地址分配机制 - 修复技术债务TD-001:FakeIP映射表无限增长问题 ```
1 parent 1d4564e commit f64bd53

File tree

7 files changed

+149
-51
lines changed

7 files changed

+149
-51
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,12 @@ setx ANTIGRAVITY_HOME "%LOCALAPPDATA%\Programs\Antigravity"
277277
278278
┌─────────────────────────────────────────────────────────────────────────┐
279279
│ 3. DNS 拦截 (DNS Interception) │
280-
│ getaddrinfo("example.com") → 分配 FakeIP (10.0.0.x) → 记录映射 │
280+
│ getaddrinfo("example.com") → 分配 FakeIP (198.18.x.x) → 记录映射 │
281281
└─────────────────────────────────────────────────────────────────────────┘
282282
283283
┌─────────────────────────────────────────────────────────────────────────┐
284284
│ 4. 连接重定向 (Connection Redirect) │
285-
│ connect(10.0.0.x) → 查询映射还原域名 → 连接代理 → SOCKS5 握手 │
285+
│ connect(198.18.x.x) → 查询映射还原域名 → 连接代理 → SOCKS5 握手 │
286286
└─────────────────────────────────────────────────────────────────────────┘
287287
288288
┌─────────────────────────────────────────────────────────────────────────┐
@@ -453,7 +453,7 @@ target_link_libraries(version PRIVATE ws2_32)
453453
},
454454
"fake_ip": {
455455
"enabled": true,
456-
"cidr": "10.0.0.0/8"
456+
"cidr": "198.18.0.0/15"
457457
},
458458
"timeout": {
459459
"connect": 5000,
@@ -490,7 +490,7 @@ target_link_libraries(version PRIVATE ws2_32)
490490
| `proxy.port` | int | `7890` | 代理服务器端口 |
491491
| `proxy.type` | string | `"socks5"` | 代理类型: `socks5``http` |
492492
| `fake_ip.enabled` | bool | `true` | 是否启用 FakeIP 系统 |
493-
| `fake_ip.cidr` | string | `"10.0.0.0/8"` | FakeIP 地址范围 |
493+
| `fake_ip.cidr` | string | `"198.18.0.0/15"` | FakeIP 地址范围 (基准测试保留网段) |
494494
| `timeout.connect` | int | `5000` | 连接超时 (毫秒) |
495495
| `timeout.send` | int | `5000` | 发送超时 (毫秒) |
496496
| `timeout.recv` | int | `5000` | 接收超时 (毫秒) |

README_EN.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -252,12 +252,12 @@ After that: PowerShell `cd $env:ANTIGRAVITY_HOME`, CMD `cd /d %ANTIGRAVITY_HOME%
252252
253253
┌─────────────────────────────────────────────────────────────────────────┐
254254
│ 3. DNS Interception │
255-
│ getaddrinfo("example.com") → Allocate FakeIP (10.0.0.x) → Save map │
255+
│ getaddrinfo("example.com") → Allocate FakeIP (198.18.x.x) → Save map │
256256
└─────────────────────────────────────────────────────────────────────────┘
257257
258258
┌─────────────────────────────────────────────────────────────────────────┐
259259
│ 4. Connection Redirect │
260-
│ connect(10.0.0.x) → Lookup mapping → Connect to proxy → SOCKS5 shake │
260+
│ connect(198.18.x.x) → Lookup mapping → Connect to proxy → SOCKS5 shake │
261261
└─────────────────────────────────────────────────────────────────────────┘
262262
263263
┌─────────────────────────────────────────────────────────────────────────┐
@@ -436,7 +436,7 @@ Edit `config.json`:
436436
},
437437
"fake_ip": {
438438
"enabled": true,
439-
"cidr": "10.0.0.0/8"
439+
"cidr": "198.18.0.0/15"
440440
},
441441
"timeout": {
442442
"connect": 5000,
@@ -469,7 +469,7 @@ Launch the target application, done! 🎉
469469
| `proxy.port` | int | `7890` | Proxy server port |
470470
| `proxy.type` | string | `"socks5"` | Proxy type: `socks5` or `http` |
471471
| `fake_ip.enabled` | bool | `true` | Enable FakeIP system |
472-
| `fake_ip.cidr` | string | `"10.0.0.0/8"` | FakeIP address range |
472+
| `fake_ip.cidr` | string | `"198.18.0.0/15"` | FakeIP address range (benchmarking reserved) |
473473
| `timeout.connect` | int | `5000` | Connection timeout (ms) |
474474
| `timeout.send` | int | `5000` | Send timeout (ms) |
475475
| `timeout.recv` | int | `5000` | Receive timeout (ms) |

build.ps1

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ $configJson = @{
258258
}
259259
fake_ip = @{
260260
enabled = $true
261-
cidr = "10.0.0.0/8"
261+
cidr = "198.18.0.0/15"
262262
}
263263
timeout = @{
264264
connect = 5000
@@ -312,7 +312,7 @@ Antigravity-Proxy 是一个基于 MinHook 的 Windows DLL 代理注入工具。
312312
},
313313
"fake_ip": {
314314
"enabled": true, // 是否启用 FakeIP 系统 (拦截 DNS 解析)
315-
"cidr": "10.0.0.0/8" // FakeIP 分配的虚拟 IP 地址范围
315+
"cidr": "198.18.0.0/15" // FakeIP 分配的虚拟 IP 地址范围 (默认为基准测试保留网段)
316316
},
317317
"timeout": {
318318
"connect": 5000, // 连接超时 (毫秒)
@@ -363,7 +363,7 @@ Test-NetConnection -ComputerName 127.0.0.1 -Port 7890
363363
| proxy.port | 代理服务器端口 | 7890 |
364364
| proxy.type | 代理类型 (socks5/http) | socks5 |
365365
| fake_ip.enabled | 是否启用 FakeIP 系统 | true |
366-
| fake_ip.cidr | 虚拟 IP 地址范围 | 10.0.0.0/8 |
366+
| fake_ip.cidr | 虚拟 IP 地址范围 | 198.18.0.0/15 |
367367
| timeout.connect | 连接超时 (毫秒) | 5000 |
368368
| timeout.send | 发送超时 (毫秒) | 5000 |
369369
| timeout.recv | 接收超时 (毫秒) | 5000 |

docs/TECH_DEBT.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@
77

88
## 🔴 高严重程度 (High Priority)
99

10-
### TD-001: FakeIP 映射表无限增长
11-
- **文件**: `src/network/FakeIP.hpp:34-49`
12-
- **问题**: `m_ipToDomain``m_domainToIp` 只增不删
13-
- **触发**: 持续解析新域名的长运行进程
14-
- **影响**: 内存持续增长,可能 OOM
15-
- **修复**: 添加 LRU 淘汰或条目上限 (建议 10000)
10+
### ~~TD-001: FakeIP 映射表无限增长~~ ✅ 已修复
11+
- **文件**: `src/network/FakeIP.hpp`
12+
- **问题**: ~~`m_ipToDomain``m_domainToIp` 只增不删~~
13+
- **状态**: **已通过 Ring Buffer 策略修复** (2026-01-11)
14+
- **修复说明**: 使用循环复用的地址池策略,游标回绕时自动覆盖旧映射并清理反向索引
1615

1716
### TD-002: ConnectEx 异步上下文泄漏
1817
- **文件**: `src/hooks/Hooks.cpp:77,212-224`

src/core/Config.hpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ namespace Core {
1616

1717
struct FakeIPConfig {
1818
bool enabled = true;
19-
std::string cidr = "10.0.0.0/8";
20-
int max_entries = 0; // 最大缓存条目数,0 表示不限制
19+
std::string cidr = "198.18.0.0/15";
20+
// 注:max_entries 已废弃,Ring Buffer 策略下自动循环复用地址池
2121
};
2222

2323
struct TimeoutConfig {
@@ -169,9 +169,8 @@ namespace Core {
169169
if (j.contains("fake_ip")) {
170170
auto& fip = j["fake_ip"];
171171
fakeIp.enabled = fip.value("enabled", true);
172-
fakeIp.cidr = fip.value("cidr", "10.0.0.0/8");
173-
int maxEntries = fip.value("max_entries", 0);
174-
fakeIp.max_entries = maxEntries < 0 ? 0 : maxEntries;
172+
fakeIp.cidr = fip.value("cidr", "198.18.0.0/15");
173+
// max_entries 已废弃,Ring Buffer 策略下无需配置上限
175174
}
176175

177176
if (j.contains("timeout")) {

src/hooks/Hooks.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
// ============= 函数指针类型定义 =============
2424
typedef int (WSAAPI *connect_t)(SOCKET, const struct sockaddr*, int);
2525
typedef int (WSAAPI *WSAConnect_t)(SOCKET, const struct sockaddr*, int, LPWSABUF, LPWSABUF, LPQOS, LPQOS);
26+
typedef struct hostent* (WSAAPI *gethostbyname_t)(const char* name);
2627
typedef int (WSAAPI *getaddrinfo_t)(PCSTR, PCSTR, const ADDRINFOA*, PADDRINFOA*);
2728
typedef int (WSAAPI *getaddrinfoW_t)(PCWSTR, PCWSTR, const ADDRINFOW*, PADDRINFOW*);
2829
typedef int (WSAAPI *send_t)(SOCKET, const char*, int, int);
@@ -48,6 +49,7 @@ typedef BOOL (WINAPI *GetQueuedCompletionStatusEx_t)(
4849
// ============= 原始函数指针 =============
4950
connect_t fpConnect = NULL;
5051
WSAConnect_t fpWSAConnect = NULL;
52+
gethostbyname_t fpGetHostByName = NULL;
5153
getaddrinfo_t fpGetAddrInfo = NULL;
5254
getaddrinfoW_t fpGetAddrInfoW = NULL;
5355
send_t fpSend = NULL;
@@ -487,6 +489,24 @@ int WSAAPI DetourGetAddrInfoW(PCWSTR pNodeName, PCWSTR pServiceName,
487489
return fpGetAddrInfoW(pNodeName, pServiceName, pHints, ppResult);
488490
}
489491

492+
struct hostent* WSAAPI DetourGetHostByName(const char* name) {
493+
auto& config = Core::Config::Instance();
494+
if (!fpGetHostByName) return NULL;
495+
496+
if (name && config.fakeIp.enabled) {
497+
std::string node = name;
498+
if (!node.empty() && !IsLoopbackHost(node) && !IsIpLiteralHost(node)) {
499+
Core::Logger::Info("拦截到域名解析(gethostbyname): " + node);
500+
uint32_t fakeIp = Network::FakeIP::Instance().Alloc(node);
501+
if (fakeIp != 0) {
502+
std::string fakeIpStr = Network::FakeIP::IpToString(fakeIp);
503+
return fpGetHostByName(fakeIpStr.c_str());
504+
}
505+
}
506+
}
507+
return fpGetHostByName(name);
508+
}
509+
490510
BOOL WSAAPI DetourWSAConnectByNameA(
491511
SOCKET s,
492512
LPCSTR nodename,
@@ -1001,6 +1021,12 @@ namespace Hooks {
10011021
Core::Logger::Error("Hook WSAConnectByNameW 失败");
10021022
}
10031023

1024+
// Hook gethostbyname
1025+
if (MH_CreateHookApi(L"ws2_32.dll", "gethostbyname",
1026+
(LPVOID)DetourGetHostByName, (LPVOID*)&fpGetHostByName) != MH_OK) {
1027+
Core::Logger::Error("Hook gethostbyname 失败");
1028+
}
1029+
10041030
// Hook WSAIoctl (用于捕获 ConnectEx)
10051031
if (MH_CreateHookApi(L"ws2_32.dll", "WSAIoctl",
10061032
(LPVOID)DetourWSAIoctl, (LPVOID*)&fpWSAIoctl) != MH_OK) {

src/network/FakeIP.hpp

Lines changed: 103 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,136 @@
11
#pragma once
22
#include <string>
3-
#include <map>
3+
#include <unordered_map>
44
#include <mutex>
5+
#include <vector>
56
#include <winsock2.h>
67
#include <ws2tcpip.h>
8+
#include <sstream>
79
#include "../core/Config.hpp"
810
#include "../core/Logger.hpp"
911

1012
namespace Network {
1113

12-
// FakeIP 管理器
13-
// 用于将域名映射到虚拟 IP (10.x.x.x),并在 connect 时还原
14+
// FakeIP 管理器 (Ring Buffer 策略)
15+
// 默认使用 198.18.0.0/15 (保留用于基准测试的网络,不容易冲突)
1416
class FakeIP {
15-
std::map<uint32_t, std::string> m_ipToDomain; // IP -> Domain 映射
16-
std::map<std::string, uint32_t> m_domainToIp; // Domain -> IP 映射 (反向查找)
17+
std::unordered_map<uint32_t, std::string> m_ipToDomain; // IP(host order) -> Domain
18+
std::unordered_map<std::string, uint32_t> m_domainToIp; // Domain -> IP(host order)
1719
std::mutex m_mtx;
18-
uint32_t m_nextIp; // 下一个可分配的 IP (主机字节序)
20+
21+
uint32_t m_baseIp; // 网段起始 IP (host order)
22+
uint32_t m_mask; // 子网掩码 (host order)
23+
uint32_t m_networkSize; // 可用 IP 数量
24+
uint32_t m_cursor; // 当前分配游标 (0 ~ networkSize-1)
25+
bool m_initialized;
26+
27+
// CIDR 解析: "198.18.0.0/15" -> baseIp, mask
28+
bool ParseCidr(const std::string& cidr, uint32_t& outBase, uint32_t& outMask) {
29+
size_t slashPos = cidr.find('/');
30+
if (slashPos == std::string::npos) return false;
31+
32+
std::string ipPart = cidr.substr(0, slashPos);
33+
std::string bitsPart = cidr.substr(slashPos + 1);
34+
35+
int bits = std::stoi(bitsPart);
36+
if (bits < 0 || bits > 32) return false;
37+
38+
in_addr addr;
39+
if (inet_pton(AF_INET, ipPart.c_str(), &addr) != 1) return false;
40+
41+
outBase = ntohl(addr.s_addr);
42+
// 这里处理 bits=0 的边界情况
43+
if (bits == 0) outMask = 0;
44+
else outMask = 0xFFFFFFFF << (32 - bits);
45+
46+
// 确保 base 是网段首地址
47+
outBase &= outMask;
48+
return true;
49+
}
1950

2051
public:
21-
FakeIP() : m_nextIp(0x0A000001) {} // 10.0.0.1 开始
52+
FakeIP() : m_baseIp(0), m_mask(0), m_networkSize(0), m_cursor(1), m_initialized(false) {}
2253

2354
static FakeIP& Instance() {
2455
static FakeIP instance;
56+
// 延迟初始化,确保 Config 已加载
57+
if (!instance.m_initialized) {
58+
instance.Init();
59+
}
2560
return instance;
2661
}
2762

28-
// 检查是否为虚拟 IP (10.0.0.0/8 范围)
63+
void Init() {
64+
std::lock_guard<std::mutex> lock(m_mtx);
65+
if (m_initialized) return;
66+
67+
auto& config = Core::Config::Instance();
68+
std::string cidr = config.fakeIp.cidr;
69+
if (cidr.empty()) cidr = "198.18.0.0/15";
70+
71+
if (ParseCidr(cidr, m_baseIp, m_mask)) {
72+
m_networkSize = ~m_mask + 1; // e.g. /24 -> 256
73+
// 保留 .0 和 .255 (广播) ? 在 FakeIP 场景下其实通常都可以用,
74+
// 但为了规避某些系统行为,跳过第0个和最后一个是个好习惯。
75+
// 简单起见,我们从 offset 1 开始使用。
76+
77+
Core::Logger::Info("FakeIP: 初始化成功, CIDR=" + cidr +
78+
", 容量=" + std::to_string(m_networkSize));
79+
} else {
80+
Core::Logger::Error("FakeIP: CIDR 解析失败 (" + cidr + "),回退到 198.18.0.0/15");
81+
ParseCidr("198.18.0.0/15", m_baseIp, m_mask);
82+
m_networkSize = ~m_mask + 1;
83+
}
84+
m_initialized = true;
85+
}
86+
87+
// 检查是否为虚拟 IP
2988
bool IsFakeIP(uint32_t ipNetworkOrder) {
89+
if (!m_initialized) Init();
3090
uint32_t ip = ntohl(ipNetworkOrder);
31-
return (ip & 0xFF000000) == 0x0A000000; // 10.x.x.x
91+
return (ip & m_mask) == m_baseIp;
3292
}
3393

34-
// 为域名分配虚拟 IP (如果已分配则返回现有 IP)
94+
// 为域名分配虚拟 IP (Ring Buffer 策略)
95+
// 返回网络字节序 IP
3596
uint32_t Alloc(const std::string& domain) {
3697
std::lock_guard<std::mutex> lock(m_mtx);
98+
if (!m_initialized) Init();
3799

38-
// 检查是否已分配
100+
// 1. 如果已存在映射,直接返回
39101
auto it = m_domainToIp.find(domain);
40102
if (it != m_domainToIp.end()) {
103+
// 可选:更新 LRU?Ring Buffer 不需要 LRU,由于空间只要够大,复用率低
41104
return htonl(it->second);
42105
}
43106

44-
// 限制缓存规模,避免无限增长
45-
int maxEntries = Core::Config::Instance().fakeIp.max_entries;
46-
if (maxEntries > 0 && m_domainToIp.size() >= static_cast<size_t>(maxEntries)) {
47-
static bool s_limitLogged = false;
48-
if (!s_limitLogged) {
49-
Core::Logger::Warn("FakeIP: 映射已达上限,后续域名将回退原始解析");
50-
s_limitLogged = true;
51-
}
52-
return 0;
107+
// 2. 分配新 IP
108+
if (m_networkSize <= 2) return 0; // 防御性检查
109+
110+
// 游标移动
111+
uint32_t offset = m_cursor++;
112+
// 简单的 Ring Buffer: 超过范围回到 1
113+
if (m_cursor >= m_networkSize - 1) {
114+
m_cursor = 1;
115+
Core::Logger::Info("FakeIP: 地址池循环回绕");
53116
}
117+
118+
uint32_t newIp = m_baseIp | offset;
119+
120+
// 3. 检查并清理旧映射 (Collision handling)
121+
auto oldIt = m_ipToDomain.find(newIp);
122+
if (oldIt != m_ipToDomain.end()) {
123+
// 把旧域名从反向表中移除
124+
m_domainToIp.erase(oldIt->second);
125+
// Core::Logger::Debug("FakeIP: 回收 IP " + IpToString(htonl(newIp)) + " (原域名: " + oldIt->second + ")");
126+
}
127+
128+
// 4. 建立新映射
129+
m_ipToDomain[newIp] = domain;
130+
m_domainToIp[domain] = newIp;
54131

55-
// 分配新 IP
56-
uint32_t ip = m_nextIp++;
57-
m_ipToDomain[ip] = domain;
58-
m_domainToIp[domain] = ip;
59-
60-
Core::Logger::Info("FakeIP: 已分配 " + IpToString(htonl(ip)) + " 给域名 " + domain);
61-
return htonl(ip); // 返回网络字节序
132+
Core::Logger::Info("FakeIP: 分配 " + IpToString(htonl(newIp)) + " -> " + domain);
133+
return htonl(newIp);
62134
}
63135

64136
// 根据虚拟 IP 获取域名
@@ -78,8 +150,10 @@ namespace Network {
78150
char buf[INET_ADDRSTRLEN];
79151
in_addr addr;
80152
addr.s_addr = ipNetworkOrder;
81-
inet_ntop(AF_INET, &addr, buf, sizeof(buf));
82-
return std::string(buf);
153+
if (inet_ntop(AF_INET, &addr, buf, sizeof(buf))) {
154+
return std::string(buf);
155+
}
156+
return "";
83157
}
84158
};
85159
}

0 commit comments

Comments
 (0)