libcurl CURLOPT_SSH_KEYDATA 详解:向 SSH 主机密钥回调传递自定义数据的完整指南

发布时间:2026/9/11 8:18:26
libcurl CURLOPT_SSH_KEYDATA 详解:向 SSH 主机密钥回调传递自定义数据的完整指南 libcurl CURLOPT_SSH_KEYDATA 详解向 SSH 主机密钥回调传递自定义数据的完整指南【免费下载链接】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导读CURLOPT_SSH_KEYDATA是 libcurl 中用于 SFTP/SCP 连接安全校验的一对配套选项之一它本身不触发任何校验逻辑而是为CURLOPT_SSH_KEYFUNCTION设置的回调提供一个**原样透传verbatim**的用户自定义指针让应用可以把任意上下文如配置结构体、日志句柄、密钥缓存等带入到主机密钥匹配回调中。读完本文你将掌握该选项的签名、在 libcurl 源码中的存储与传递路径、与回调及其返回值的关系以及一套可直接编译运行的最小示例。选项定位它是数据通道而非校验开关在 libcurl 的 SSH 校验体系里CURLOPT_SSH_KEYDATA官方文档承担的角色非常单一且明确Pass a void * as parameter. Thispointeris passed along verbatim to the callback set with CURLOPT_SSH_KEYFUNCTION(3).即你传进去的void *指针会被 libcurl 原封不动地交给通过CURLOPT_SSH_KEYFUNCTION注册的回调函数作为其最后一个参数clientp出现。它不影响校验结果本身校验决策完全由回调函数根据收到的四个参数做出。它只在 SFTP 和 SCP 两个协议下生效该选项在文档中声明支持Protocol: SFTP, SCP从 7.19.6 版本开始提供。函数签名#include curl/curl.h CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_KEYDATA, void *pointer);handle通过curl_easy_init()获得的 easy handle。pointer任意用户指针可以为NULL。返回值CURLcodeCURLE_OK (0)表示设置成功非零值表示出错参见 libcurl-errors。在 libcurl 的选项注册表 lib/easyoptions.c 中该选项的类型被登记为CURLOT_CBPTRcallback pointer说明它属于伴随回调使用的指针一类与SSH_KEYFUNCTIONCURLOT_FUNCTION成对出现。源码视角从 setopt 到回调的完整传递链1. 存储setopt阶段在 lib/setopt.c 中可以看到该选项的唯一处理逻辑case CURLOPT_SSH_KEYDATA: /* * Custom client data to pass to the SSH keyfunc callback */ s-ssh_keyfunc_userp ptr; break;它只是把指针存入 easy handle 的set结构体成员ssh_keyfunc_userp不做任何拷贝、校验或转换——这正符合原样透传的语义。2. 承载easy handle 数据结构在 lib/urldata.h 中该成员与回调函数指针紧邻存放#ifdef USE_SSH curl_sshkeycallback ssh_keyfunc; /* key matching callback */ void *ssh_keyfunc_userp; /* custom pointer to callback */ uint32_t ssh_auth_types; /* allowed SSH auth types */ ... #endif注意它被#ifdef USE_SSH包裹只有在编译 libcurl 时启用了 SSH 后端libssh2 或 libssh的情况下该选项才实际生效。3. 回调签名与参数语义回调类型在 include/curl/curl.h 中定义enum curl_khtype { CURLKHTYPE_UNKNOWN, CURLKHTYPE_RSA1, CURLKHTYPE_RSA, CURLKHTYPE_DSS, CURLKHTYPE_ECDSA, CURLKHTYPE_ED25519 }; struct curl_khkey { const char *key; /* base64 编码字符串若 len 非零则为 raw 原始数据 */ size_t len; enum curl_khtype keytype; }; typedef int (*curl_sshkeycallback)(CURL *easy, const struct curl_khkey *knownkey, /* known_hosts 中的密钥 */ const struct curl_khkey *foundkey, /* 远端主机下发的密钥 */ enum curl_khmatch, /* libcurl 对匹配状态的判断 */ void *clientp); /* 由 CURLOPT_SSH_KEYDATA 传入 */回调的最后一个参数clientp正是CURLOPT_SSH_KEYDATA存入的ssh_keyfunc_userp。当未设置该选项时clientp为NULL——所以回调内部要做空指针防御。4. 实际调用点两个 SSH 后端libcurl 支持两种 SSH 实现后端二者在调用回调时都把data-set.ssh_keyfunc_userp作为最后一个实参传入libssh2 后端lib/vssh/libssh2.clibssh 后端lib/vssh/libssh.c两处代码都以类似形式调用rc func(data, knownkeyp, /* from the knownhosts file */ foundkey, /* from the remote host */ keymatch,>struct mine { void *custom; }; static int keycb(CURL *easy, const struct curl_khkey *knownkey, const struct curl_khkey *foundkey, enum curl_khmatch match, void *clientp) { /* clientp points to the callback_data struct */ /* investigate the situation and return the correct value */ return CURLKHSTAT_FINE_ADD_TO_FILE; } int main(void) { CURL *curl curl_easy_init(); if(curl) { CURLcode result; struct mine callback_data; curl_easy_setopt(curl, CURLOPT_URL, sftp://example.com/thisfile.txt); curl_easy_setopt(curl, CURLOPT_SSH_KEYFUNCTION, keycb); curl_easy_setopt(curl, CURLOPT_SSH_KEYDATA, callback_data); curl_easy_setopt(curl, CURLOPT_SSH_KNOWNHOSTS, /home/user/known_hosts); result curl_easy_perform(curl); curl_easy_cleanup(curl); } }示例要点callback_data是栈上分配的结构体通过callback_data传入CURLOPT_SSH_KEYDATA回调中通过clientp拿回该结构体指针即可访问应用自定义数据CURLOPT_SSH_KNOWNHOSTS必须一并设置否则回调不会被触发详见 CURLOPT_SSH_KEYFUNCTION 中 The callback is only called if CURLOPT_SSH_KNOWNHOSTS(3) is also set 的说明回调返回CURLKHSTAT_FINE_ADD_TO_FILE表示信任该主机并把密钥写入 known_hosts典型的 trust on first use 场景。与相关选项的组合使用从 lib/vssh/libssh.c 的注释可以看到libcurl 对 SSH 主机密钥校验提供了一条优先级链设置了CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256按 SHA256 哈希校验设置了CURLOPT_SSH_HOST_PUBLIC_KEY_MD5按 MD5 哈希校验设置了CURLOPT_SSH_KEYFUNCTION回调做 trust-on-first-use若回调返回CURLKHSTAT_FINE_ADD_TO_FILE还会写入 known_hosts以上均未设置仅当主机已存在于 known_hosts 时才接受。CURLOPT_SSH_KEYDATA属于第 3 条路径的辅助数据通道。配合CURLOPT_SSH_KNOWNHOSTSknown_hosts 文件路径一起使用可以让应用在回调中同时拿到known_hosts 中的已知密钥、远端下发的实际密钥、libcurl 的匹配判断CURLKHMATCH_OK/MISMATCH/MISSING以及自定义上下文四个维度的信息从而自行决定放行、拒绝或写入。测试用例佐证仓库测试 tests/data/test1459 提供了 SFTP with corrupted known_hosts 的真实验证场景它通过 curl 命令行--knownhosts %LOGDIR/known%TESTNUMBER指向一个内容被篡改的 known_hosts 文件该命令行选项对应的正是CURLOPT_SSH_KNOWNHOSTS并期望连接以错误码60CURLE_PEER_FAILED_VERIFICATION失败。这从侧面印证了 known_hosts 校验失败时的行为路径即使不经过用户回调libcurl 也会在密钥不匹配时拒绝继续连接。而一旦你设置了CURLOPT_SSH_KEYFUNCTIONCURLOPT_SSH_KEYDATA这个拒绝的决策权就交还给了你的回调。默认值与返回值默认值NULL。未设置时回调收到的clientp为NULL回调中需自行处理。curl_easy_setopt返回值CURLE_OK (0)表示设置成功非零表示错误具体错误码参见 libcurl-errors。实践建议生命周期管理CURLOPT_SSH_KEYDATA只保存指针不拷贝内容。传入的数据必须保证在curl_easy_perform返回之前一直有效栈上结构体、静态变量、堆上对象均可但不要在回调返回后继续使用被释放的指针。空指针防御回调第一个参数easy、knownkey在主机不在 known_hosts 中时为NULL以及clientp未设置 KEYDATA 时都可能为NULL引用前务必判空。多线程注意该选项是 easy handle 级配置不同 easy handle 之间互不影响但同一 handle 不应在多线程中并发执行curl_easy_perform。文件写入权限若回调返回CURLKHSTAT_FINE_ADD_TO_FILE或CURLKHSTAT_FINE_REPLACElibcurl 会以整文件重写方式更新 known_hosts 文件因此该文件所在目录及文件本身必须有相应写权限否则写入会失败libcurl 仅记录infof警告不会中断连接。总结CURLOPT_SSH_KEYDATA是一个极简但关键的配套选项它把 libcurl 的主机密钥校验机制从内置默认行为扩展为应用可控策略。借助它开发者可以在 SFTP/SCP 场景下实现自定义的 known_hosts 策略如首连信任、密钥轮换替换、审计日志记录等而其底层传递路径——从 lib/setopt.c 的存储、lib/urldata.h 的承载到两个 SSH 后端 lib/vssh/libssh2.c 与 lib/vssh/libssh.c 的调用——构成了一个完整、可追踪的实现闭环。【免费下载链接】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),仅供参考