的发送字节数)
curl 中 CURLINFO_EARLYDATA_SENT_T 详解用 libcurl 量化 TLS 1.3 Early Data0-RTT的发送字节数【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl本篇围绕 libcurl 的信息查询选项CURLINFO_EARLYDATA_SENT_T展开它告诉你在一次传输中究竟有多少字节是以 TLSv1.3 early data即 0-RTT形式发给服务器的。读完本文你将掌握如何通过curl_easy_getinfo()读取该值、如何正确解读正值、0 与负值三种语义并能结合 curl 仓库源码理解 early data 的完整生命周期——从CURLSSLOPT_EARLYDATA开关、TLS 会话缓存到各 TLS 后端对“服务器接受/拒绝”状态的判定以及命令行下--tls-earlydata与%{tls_earlydata}的对应用法。一、这个 getinfo 选项是什么CURLINFO_EARLYDATA_SENT_T是一个CURLINFO_OFF_T类型的信息项通过curl_easy_getinfo()查询自8.11.0版本加入见 CURLINFO_EARLYDATA_SENT_T.md 文档头部的Added-in与Protocol: TLS元数据。其原型为#include curl/curl.h CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_EARLYDATA_SENT_T, curl_off_t *amount);在头文件 include/curl/curl.h 中它的枚举定义为CURLINFO_EARLYDATA_SENT_T CURLINFO_OFF_T 68,类型是CURLINFO_OFF_T因此传入的指针必须是curl_off_t *——这一点在跨平台32 位/64 位代码里尤其重要直接决定取回值的宽度。返回值语义0、正数、负数官方文档给出的语义可以归纳为三种情况取回值含义0本次传输根本没有使用 TLS early data正数 N有 N 字节以 early data 形式发出且未被服务器拒绝负数 -N发送了 N 字节的 early data但被服务器拒绝文档特别强调TLS 规范允许服务器在宣布支持 early data 之后仍凭自己的意愿拒绝任何 early data 尝试。例如发出了 127 字节但被拒绝时该值报告为-127。这个负号设计让调用方无需额外状态位即可判断 early data 是否真正生效。二、前提条件什么时候才会有 non-zero 的 early data文档明确指出early data 只有在同时满足以下条件时才会被尝试调用方显式开启为传输设置了CURLSSLOPT_EARLYDATA通过curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_EARLYDATA)。该标志位定义在 include/curl/curl.h/* If possible, send data using TLS 1.3 early data */ #define CURLSSLOPT_EARLYDATA (1L 6)根据 CURLOPT_SSL_OPTIONS.md 的说明此选项在 GnuTLS、OpenSSL、quictls 和 wolfSSL 后端受支持不支持 AWS-LC 和 BoringSSL并可在 TCP 和基于 ngtcp2 的 QUIC 连接上工作。存在宣布支持 early data 的既有 TLS 会话服务器对 early data 的支持是在 TLS 会话票据中随前一次握手“捎带”告知的。也就是说第一次访问某主机不可能使用 0-RTT——必须复用之前收到的、带有 early data 通告的会话。这正是 curl 8.12.0 引入的 SSLS-EXPORT / --ssl-sessions 命令行的意义把会话票据持久化到文件下次运行时重新加载使--tls-earlydata有机会在首个请求上就以 0-RTT 模式发出数据。best-effort 性质即使条件都满足如果 early data 无法发送请求会被重新发送走完整的 1-RTT 握手后再发不会导致传输失败此时该值通常报告为 0。三、最小可用示例下面完整继承官方文档给出的示例并补充说明每一处要点int main(void) { CURL *curl curl_easy_init(); if(curl) { CURLcode result; curl_easy_setopt(curl, CURLOPT_URL, https://example.com); /* Perform the request */ result curl_easy_perform(curl); if(result CURLE_OK) { curl_off_t amount; result curl_easy_getinfo(curl, CURLINFO_EARLYDATA_SENT_T, amount); if(result CURLE_OK) { printf(TLS earlydata: % CURL_FORMAT_CURL_OFF_T bytes\n, amount); } } } }要点必须用CURL_FORMAT_CURL_OFF_T宏而非%lld来格式化curl_off_t保证不同平台上宽度正确——这一点在 tests/libtest/cli_hx_download.c 的测试代码里同样是这么写的查询必须在curl_easy_perform()完成之后进行因为该值反映的是“本次传输已发生”的统计结果返回值遵循curl_easy_getinfo(3)的约定CURLE_OK(0) 表示成功非 0 表示错误详见 RETURN VALUE 一节。四、源码剖析这个数值从哪里来4.1 getinfo 只是读取一个统计字段在 lib/getinfo.c 中CURLINFO_EARLYDATA_SENT_T的处理极其简单直接从传输句柄的进度结构里取字段case CURLINFO_EARLYDATA_SENT_T: *param_offt >void Curl_pgrsEarlyData(struct Curl_easy *data, curl_off_t sent) { >typedef enum { ssl_earlydata_none, ssl_earlydata_await, ssl_earlydata_sending, ssl_earlydata_sent, ssl_earlydata_accepted, ssl_earlydata_rejected } ssl_earlydata_state;握手完成后lib/vtls/vtls.c 根据最终状态决定是否记账并顺带解释了负值来源switch(connssl-earlydata_state) { case ssl_earlydata_none: break; case ssl_earlydata_accepted: if(!Curl_ssl_cf_is_proxy(cf)) Curl_pgrsEarlyData(data, (curl_off_t)connssl-earlydata_skip); infof(data, Server accepted %zu bytes of TLS early data., ...); break; case ssl_earlydata_rejected: if(!Curl_ssl_cf_is_proxy(cf)) Curl_pgrsEarlyData(data, -(curl_off_t)connssl-earlydata_skip); infof(data, Server rejected TLS early data.); connssl-earlydata_skip 0; break; ... }两个值得注意的细节代理连接不计入Curl_ssl_cf_is_proxy(cf)为真时跳过记账。因为 curl 与前置 TLS 代理之间的 early data 与目标服务器之间的语义不同该统计面向的是最终服务器传输每个 TLS 后端各自负责把ssl_earlydata_sent推进到accepted/rejected判定依据来自各自 TLS 库的接口GnuTLS 在 lib/vtls/gtls.c 通过gnutls_session_get_flags()检查GNUTLS_SFLAGS_EARLY_DATA标志OpenSSL 在 lib/vtls/openssl.c 用SSL_get_early_data_status()与SSL_EARLY_DATA_ACCEPTED比较wolfSSL 在 lib/vtls/wolfssl.c 检查wolfSSL_get_early_data_status()是否等于WOLFSSL_EARLY_DATA_REJECTEDQUICngtcp2路径在 lib/vquic/cf-ngtcp2-cmn.c 中直接按“接受/未接受”分别传入正负值CURL_TRC_CF(data, cf, server did%s accept %zu bytes of early data, ctx-earlydata_accepted ? : not, ctx-earlydata_skip); Curl_pgrsEarlyData(data, ctx-earlydata_accepted ? (curl_off_t)ctx-earlydata_skip : -(curl_off_t)ctx-earlydata_skip);注意 QUIC 分支是一次性地根据接受与否直接写入带符号值而 TCP 分支则分“发送时先记正值、拒绝后改为负值”两步但最终暴露给用户的语义一致。4.4 调试输出中的旁证开启CURLOPT_VERBOSE时verbose 日志会输出 “Server accepted N bytes of TLS early data.” 或 “Server rejected TLS early data.”见上文 lib/vtls/vtls.c 中的infof()调用方便你在集成该 getinfo 之前先在终端层面交叉验证行为是否符合预期。五、命令行下的对应物--tls-earlydata 与 %{tls_earlydata}curl 命令行把这一能力暴露为一对配套选项开启开关--tls-earlydata8.11.0 加入与 libcurl 同一版本“尽可能使用 TLSv1.3 early data也叫 0-RTT”观测数值--write-out 变量tls_earlydata。二者的映射在 src/tool_writeout.c 中一目了然{ tls_earlydata, VAR_TLS_EARLYDATA_SENT, CURLINFO_EARLYDATA_SENT_T, writeOffset },即命令行的%{tls_earlydata}最终调用的正是本文主角CURLINFO_EARLYDATA_SENT_T。一个可复制的典型用法配合持久化会话文件# 第一次访问建立并保存带 early data 通告的 TLS 会话 curl --ssl-sessions sessions.txt --tls-earlydata https://example.com # 再次访问若命中缓存中的合格会话首请求以 0-RTT 发出 curl --ssl-sessions sessions.txt --tls-earlydata https://example.com \ -w early data sent: %{tls_earlydata} bytes\n输出中该变量为 0 表示本次没有走 early data负数表示发出了但被服务器拒绝正数则是真正以 0-RTT 送达的字节数。六、安全提醒0-RTT 的语义边界文档与 tls-earlydata.md 一致地给出了安全警告写代码时应当把这些约束传递给你的用户early data 虽然经过加密但不受重放保护攻击者可以把你的 early data 再次发给服务器服务器会照单全收。对“只读一个公开文件”的请求可能无伤大雅但对有副作用的操作如下单则不应使用early data不提供前向保密见 ssl-sessions.md安全性弱于常规 1-RTT 数据curl 不会替你判断某个请求的 early data 风险决策在调用方。因此程序里读到负值或 0 时应按“未生效”处理业务逻辑而不是当作错误。七、回归验证仓库内如何使用该选项仓库测试框架自带了一个直接验证该功能的命令行工具 tests/libtest/cli_hx_download.c其-e参数设置CURLSSLOPT_EARLYDATA见 第 249-250 行并在每个传输结束后查询并打印该值if(use_earlydata) { curl_off_t sent; curl_easy_getinfo(easy, CURLINFO_EARLYDATA_SENT_T, sent); curl_mfprintf(stderr, [t-%zu] EarlyData: % CURL_FORMAT_CURL_OFF_T \n, t-idx, sent); }第 510-515 行配合 tests/libtest/cli_hx_upload.c 中的上传变体可以在本地测试环境里端到端地复现“发送—被接受/被拒绝—数值回报”的完整链路。八、小结CURLINFO_EARLYDATA_SENT_T8.11.0 起CURLINFO_OFF_T类型是 libcurl 暴露的、用于量化 TLS 1.3 early data 实际发送字节数的唯一官方查询项语义三分0 未使用正数 发出的字节数负数 发出但被服务器拒绝的字节数源码层面为earlydata_sent直接覆盖写入见 lib/progress.c生效前提是CURLSSLOPT_EARLYDATA 缓存中存在宣布支持 early data 的 TLS 会话命令行对应--tls-earlydata与%{tls_earlydata}各 TLS 后端GnuTLS/OpenSSL/wolfSSL/ngtcp2分别用自己的接口判定接受/拒绝最终在 lib/vtls/vtls.c 或 QUIC 层统一折算成该统计值代理连接不计入统计使用 0-RTT 前必须评估重放与前向保密缺失带来的安全影响curl 本身不做此判断。【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考