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域名处理 端口有效性检查 内存化配置对象

💾 关键配置数据结构
cpp 复制代码
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域名有效性示例:
cpp 复制代码
if (reverse_host.size()) {
    std::size_t index = reverse_host.find('.');
    if (index == std::string::npos) {
        reverse_host.clear(); // 无效域名
    }
}
  • CDN节点地址转换:
cpp 复制代码
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上下文分配
cpp 复制代码
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_;
}
⏱️ 超时管理机制
cpp 复制代码
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提取关键代码
cpp 复制代码
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头提取示例代码
cpp 复制代码
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地址(环回/组播) 拒绝连接 -

🔑 域名匹配算法

cpp 复制代码
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;
}

🔑 端点选择逻辑

cpp 复制代码
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()

cpp 复制代码
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 源服务器

🔑 节点选择算法

cpp 复制代码
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 通过架构创新深度优化,实现了:

  • 🚀 高性能:零拷贝、智能内存池
  • 🔐 安全保障:分层防御、协议校验、隐私保护
  • 高可靠:智能路由、健康检查
  • 🌱 易扩展:模块化、插件系统
相关推荐
Eiceblue39 分钟前
【免费.NET方案】CSV到PDF与DataTable的快速转换
开发语言·pdf·c#·.net
tan180°1 小时前
MySQL表的操作(3)
linux·数据库·c++·vscode·后端·mysql
m0_555762901 小时前
Matlab 频谱分析 (Spectral Analysis)
开发语言·matlab
浪裡遊2 小时前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
彭祥.3 小时前
Jetson边缘计算主板:Ubuntu 环境配置 CUDA 与 cudNN 推理环境 + OpenCV 与 C++ 进行目标分类
c++·opencv·分类
lzb_kkk3 小时前
【C++】C++四种类型转换操作符详解
开发语言·c++·windows·1024程序员节
好开心啊没烦恼3 小时前
Python 数据分析:numpy,说人话,说说数组维度。听故事学知识点怎么这么容易?
开发语言·人工智能·python·数据挖掘·数据分析·numpy
ai小鬼头3 小时前
AIStarter如何助力用户与创作者?Stable Diffusion一键管理教程!
后端·架构·github
简佐义的博客4 小时前
破解非模式物种GO/KEGG注释难题
开发语言·数据库·后端·oracle·golang