SNIProxy 轻量级匿名CDN代理架构与实现

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;          // TCP快速打开
    
    struct {
        bool lan;            // 局域网优化
        bool wan;            // 广域网优化
    } turbo;
    
    struct {
        int http;            // HTTP监听端口
        int http_ssl;        // HTTPS监听端口
    } listen;
    
    struct {
        std::string host;    // CDN主域名
        std::string http;    // HTTP CDN节点
        std::string http_ssl;// HTTPS CDN节点
    } reverse_proxy;
    
    struct {
        int timeout;         // 连接超时(秒)
    } connect;
};
配置验证算法
  • 端口范围:1-65535
  • CDN域名有效性示例:
if (reverse_host.size()) {
    std::size_t index = reverse_host.find('.');
    if (index == std::string::npos) {
        reverse_host.clear(); // 无效域名
    }
}
  • CDN节点地址转换:
IPEndPoint ipep = Ipep::GetEndPoint(reverse_server, false);
if (!IPEndPoint::IsInvalid(ipep)) {
    // 转换为标准IP:PORT格式
}

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 ""; // 非ClientHello
    
    int length = fetch_length(data);
    data += 2; // 跳过版本
    data += 32; // 跳过Random
    
    // 处理Session ID
    Byte session_len = *data++;
    data += session_len;
    
    // 处理Cipher Suites
    int cipher_len = fetch_uint16(data);
    data += cipher_len;
    
    // 处理Extensions
    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) { // SNI扩展
            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");
    
    // 解析请求行: METHOD URI VERSION
    std::vector<std::string> request_line;
    Tokenize(headers[0], request_line, " ");
    
    if (request_line.size() < 3) return "";
    
    // 检查URI格式
    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);
    }
    
    // 查找Host头
    for (size_t i = 1; i < headers.size(); i++) {
        if (headers[i].find("Host:") == 0) {
            return headers[i].substr(6); // "Host: "长度
        }
    }
    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) {
        // 实现TCP/HTTP健康检查
        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通过架构创新深度优化,实现了:

  • 高性能:零拷贝、智能内存池
  • 安全保障:分层防御、协议校验、隐私保护
  • 高可靠:智能路由、健康检查
  • 易扩展:模块化、插件系统

你可能感兴趣的:(Markdown,C/C++,PROXY,架构,c++,网络,开发语言,通信,网关,cdn)