SNIProxy 轻量级匿名CDN代理架构与实现
️ 1. 整体架构设计
1.1 系统架构概览
SNIProxy核心架构
HTTP 80
HTTPS 443
CDN域名
直连域名
协议分发层
SNIProxy核心
HTTP处理引擎
TLS处理引擎
HTTP头解析
SNI提取
路由决策引擎
CDN转发器
直连转发器
CDN节点池
目标服务器
数据转发引擎
客户端
响应处理
配置管理
性能监控
1.2 组件交互关系
客户端 监听器(server) SNIProxy(sniproxy) 解析器(Ipep) 目标服务器 TCP连接(80/443) 创建代理会话 协议检测(HTTP/TLS) 解析Host头 提取SNI扩展 alt [HTTP协议] [TLS协议] 域名解析 返回IP地址 CDN路由决策 连接到CDN节点 直连目标服务器 alt [CDN路由] [直连] 建立双向通道 请求数据 转发请求 响应数据 转发响应 客户端 监听器(server) SNIProxy(sniproxy) 解析器(Ipep) 目标服务器
⚙️ 2. 核心模块深度分析
2.1 配置管理系统
⚡ 配置加载流程
是
否
启动参数
配置文件路径
文件存在?
读取JSON内容
使用默认配置
JSON解析
配置项验证
CDN域名处理
端口有效性检查
内存化配置对象
关键配置数据结构
class server_configuration {
public:
int concurrent;
int backlog;
bool fast_open;
struct {
bool lan;
bool wan;
} turbo;
struct {
int http;
int http_ssl;
} listen;
struct {
std::string host;
std::string http;
std::string http_ssl;
} reverse_proxy;
struct {
int timeout;
} connect;
};
配置验证算法
if (reverse_host.size()) {
std::size_t index = reverse_host.find('.');
if (index == std::string::npos) {
reverse_host.clear();
}
}
IPEndPoint ipep = Ipep::GetEndPoint(reverse_server, false);
if (!IPEndPoint::IsInvalid(ipep)) {
}
2.2 网络IO核心(Hosting)
线程模型
管理
1
*
Hosting
-int concurrent_
-ContextList contexts_
-Mutex lockobj_
+GetContext()
+Timeout()
io_context_wrapper
-boost::asio::io_context context
-std::thread worker_thread
+run()
IO上下文分配
std::shared_ptr<boost::asio::io_context> Hosting::GetContext() noexcept {
MutexScope scope_(lockobj_);
if (contexts_.empty()) return nullptr;
auto context_ = contexts_.front();
contexts_.pop_front();
contexts_.push_back(context_);
return context_;
}
⏱️ 超时管理机制
bool Hosting::WaitTimeout() noexcept {
timeout_->expires_from_now(boost::posix_time::milliseconds(10));
timeout_->async_wait([this](const boost::system::error_code& ec) {
if (!ec) {
now_ += 10;
WaitTimeout();
}
});
return true;
}
2.3 协议处理引擎
2.3.1 TLS流程图
0x01
是
否
接收ClientHello
验证记录类型=0x16
读取TLS长度
加载完整握手消息
解析Handshake类型
解析ClientHello
跳过Random32字节
处理SessionID
跳过CipherSuites
跳过CompressionMethods
解析Extensions
找到SNI扩展?
提取主机名
返回空字符串
SNI提取关键代码
std::string sniproxy::fetch_sniaddr(size_t tls_payload) noexcept {
Byte* data = (Byte*)local_socket_buf_;
if (*data++ != 0x01) return "";
int length = fetch_length(data);
data += 2;
data += 32;
Byte session_len = *data++;
data += session_len;
int cipher_len = fetch_uint16(data);
data += cipher_len;
int extensions_len = fetch_uint16(data);
Byte* extensions_end = data + extensions_len;
while (data < extensions_end) {
int ext_type = fetch_uint16(data);
int ext_len = fetch_uint16(data);
if (ext_type == 0x0000) {
int name_list_len = fetch_uint16(data);
int name_type = *data++;
if (name_type != 0x00) continue;
int name_len = fetch_uint16(data);
return std::string((char*)data, name_len);
}
data += ext_len;
}
return "";
}
2.3.2 HTTP处理流程
完整URL
路径
是
否
接收请求行
解析方法+URI+版本
URI格式检查
提取主机部分
查找Host头
返回主机名
遍历头部
找到Host头?
提取主机名
返回空
Host头提取示例代码
std::string sniproxy::do_httpd_handshake_host(MemoryStream& messages_) {
std::vector<std::string> headers;
Tokenize(std::string((char*)messages_.GetBuffer().get()), headers, "\r\n");
std::vector<std::string> request_line;
Tokenize(headers[0], request_line, " ");
if (request_line.size() < 3) return "";
const std::string& uri = request_line[1];
if (uri.find("://") != std::string::npos) {
size_t pos = uri.find("://") + 3;
size_t end = uri.find('/', pos);
if (end == std::string::npos)
return uri.substr(pos);
else
return uri.substr(pos, end - pos);
}
for (size_t i = 1; i < headers.size(); i++) {
if (headers[i].find("Host:") == 0) {
return headers[i].substr(6);
}
}
return "";
}
3. 路由决策引擎
路由示意表
条件 |
动作 |
目标端点 |
主机匹配CDN域名且协议为HTTP |
转发到CDN |
reverse_proxy.http |
主机匹配CDN域名且协议为HTTPS |
转发到CDN |
reverse_proxy.http_ssl |
主机不匹配CDN域名 |
直连 |
解析的IP地址 |
无效主机名 |
拒绝连接 |
- |
保留IP地址(环回/组播) |
拒绝连接 |
- |
域名匹配算法
bool sniproxy::be_host(std::string host, std::string domain) noexcept {
host = ToLower(RTrim(LTrim(host)));
domain = ToLower(RTrim(LTrim(domain)));
if (host == domain) return true;
std::vector<std::string> labels;
if (Tokenize(domain, labels, ".") < 2) return false;
std::vector<std::string> host_labels;
Tokenize(host, host_labels, ".");
if (host_labels.size() <= labels.size()) return false;
size_t diff = host_labels.size() - labels.size();
for (size_t i = 0; i < labels.size(); i++) {
if (host_labels[i + diff] != labels[i])
return false;
}
return true;
}
端点选择逻辑
IPEndPoint sniproxy::select_endpoint(
const std::string& hostname,
int port,
bool is_https) noexcept
{
if (be_host(hostname, configuration_->reverse_proxy.host)) {
const std::string& cdn_node = is_https ?
configuration_->reverse_proxy.http_ssl :
configuration_->reverse_proxy.http;
return Ipep::GetEndPoint(cdn_node, false);
}
boost::system::error_code ec;
boost::asio::ip::address address =
boost::asio::ip::address::from_string(hostname, ec);
if (ec) {
return Ipep::GetEndPoint(hostname, port, true);
}
return IPEndPoint(address.to_string().c_str(), port);
}
4. 性能优化体系
4.1 网络栈优化
参数 |
选项 |
适用场景 |
示例代码 |
TCP_NODELAY |
开启 |
高吞吐/低延迟 |
socket->set_option(no_delay(true)) |
TCP_FASTOPEN |
开启 |
连接快速建立 |
setsockopt(IPPROTO_TCP, TCP_FASTOPEN, ...) |
IP_TOS |
0x68 |
QoS优化 |
setsockopt(SOL_IP, IP_TOS, 0x68) |
SO_REUSEADDR |
开启 |
端口复用 |
acceptor->set_option(reuse_address(true)) |
IP_DONTFRAG |
禁用 |
路径MTU发现 |
setsockopt(IPPROTO_IP, IP_DONTFRAG, 0) |
️ 4.2 内存管理优化
MemoryStream
-std::shared_ptr _buffer
-int _position
-int _length
-int _capacity
+Write(const void*, int, int)
+Read(void*, int, int)
+GetBuffer()
template<typename T>
std::shared_ptr<T> make_shared_alloc(int length) noexcept {
if (length < 1) return nullptr;
size_t aligned_size = (length * sizeof(T) + 15) & ~15;
#ifdef JEMALLOC
T* p = (T*)je_malloc(aligned_size);
#else
T* p = (T*)malloc(aligned_size);
#endif
return std::shared_ptr<T>(p, [](T* ptr) {
if (ptr) {
#ifdef JEMALLOC
je_free(ptr);
#else
free(ptr);
#endif
}
});
}
️ 5. CDN转发机制深度解析
CDN架构示意图
CDN域名
客户端
SNIProxy
路由决策
CDN适配层
节点选择策略
健康检查
负载均衡
CDN节点1
CDN节点2
CDN节点3
源服务器
节点选择算法
class CDNSelector {
public:
struct Node {
IPEndPoint endpoint;
int weight;
int current_connections;
std::chrono::steady_clock::time_point last_checked;
bool healthy;
};
CDNSelector(const std::vector<IPEndPoint>& nodes) {
for (const auto& ep : nodes) {
available_nodes.push_back({ep, 10, 0,
std::chrono::steady_clock::now(), true});
}
}
IPEndPoint select_node() {
auto now = std::chrono::steady_clock::now();
for (auto& node : available_nodes) {
if (now - node.last_checked > std::chrono::seconds(30)) {
node.healthy = check_node_health(node.endpoint);
node.last_checked = now;
}
}
Node* selected = nullptr;
int min_score = std::numeric_limits<int>::max();
for (auto& node : available_nodes) {
if (!node.healthy) continue;
int score = node.current_connections * 100 / node.weight;
if (score < min_score) {
min_score = score;
selected = &node;
}
}
if (selected) {
selected->current_connections++;
return selected->endpoint;
}
throw std::runtime_error("No available CDN nodes");
}
private:
bool check_node_health(const IPEndPoint& ep) {
return true;
}
std::vector<Node> available_nodes;
};
6. 安全机制深度分析
️ 威胁模型
- DDoS攻击(SYN洪水、连接耗尽)
- 协议攻击(畸形TLS/HTTP包)
- 信息泄露(内存暴露、错误信息)
- 中间人攻击(TLS拦截)
- 资源耗尽(文件描述符、内存)
️ 防御措施
网络层
连接限制
SYN Cookies
Backlog队列管理
协议层
严格格式校验
超时控制
5秒连接超时
应用层
内存隔离
安全关闭
双重关闭验证
运维层
权限最小化
实时监控
✅ 7. 扩展性与未来演进
可扩展架构
IPlugin
+on_connection_start()
+on_headers_parsed()
+on_data_received()
+on_connection_end()
ProtocolPlugin
+on_connection_start()
RoutingPlugin
+on_headers_parsed()
LoggingPlugin
+on_connection_end()
SNIProxyCore
-std::vector plugins
+register_plugin(IPlugin*)
+notify_event(EventType)
结论
SNIProxy通过架构创新和深度优化,实现了:
- 高性能:零拷贝、智能内存池
- 安全保障:分层防御、协议校验、隐私保护
- ✅ 高可靠:智能路由、健康检查
- 易扩展:模块化、插件系统