1 背景
? ? 最近用libevent寫了一個https代理功能,在調研的時候,遇到了一個項目用到了本地多個openssl庫引發的ssl握手崩潰問題。
2 開發環境
項目庫 | 版本號 | 依賴項 |
libevent | libevent-2.1.8-stable | openssl 1.1 |
openssl | 1.0u / 1.1.1w / 3.3.1 | ...... |
3 問題現象
? ? https代理的下游是http客戶端( 播放器)連接,上游服務器是https對接,其中https對接上游需要用到openssl庫。
? ? 這在播放器打開該播放url并回溯到上游點播服務器的=的時候,崩潰堆棧直接到了openssl庫內部。
? ? 以下是出問題時的堆棧現場:
4 原因分析
? ??為了簡單起見,抽離了業務代碼,直接用openssl的api寫了一個簡單的demo,去連接上游https服務器,發現同樣存在崩潰現象,并且崩潰的堆棧都一樣。
? ? 列出demo的主要代碼:
int main (int argc, char* argv[]) {/* 初始化SSL協議環境 */// SSL_library_int();/* 創建SSL上下文 */SSL_CTX *ctx = SSL_CTX_new (SSLv23_client_method());if(ctx == NULL) {return false;}/* 設置SSL選項 */SSL_CTX_set_options (ctx,SSL_OP_SINGLE_DH_USE |SSL_OP_SINGLE_ECDH_USE |SSL_OP_NO_SSLv2 /*禁用SSLv2*/ |SSL_OP_NO_TLSv1 /*禁用TLSv1*/);// 不校驗ssl證書SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);int r = bufferevent_openssl_socket_new (base,-1,SSL_new(ctx),BUFFEREVENT_SSL_ACCEPTING,BEV_OPT_CLOSE_ON_FREE);// 設置回調函數bufferevent_setcb(evcon->bufev, evhttp_read_cb, evhttp_write_cb, evhttp_ssl_error_cb, evcon);// 啟動SSL連接bufferevent_socket_connect_hostname(evcon->bufev, dnsbase, AF_UNSPEC, evcon->address, port);bufferevent_enable(evcon->bufev, EV_WRITE);struct event_base* event_base = event_base_new();event_base_dispatch(event_base);SSL_CTX_free(ssl_ctx);return 0;
}
?問題原因,當時有2個方向:
- openssl的api使用不當所致,經openssl的example對比發現無異常;
- 本地或有多個openssl版本,libevent-2.1.8-stable的編譯和鏈接用到了不同的openssl庫所致;
? ?終端執行ls命令查看,的確有多個openssl版本(其實還有openssl的1.0u版本,后來為解決問題卸載了):
5 解決辦法
? ? 由于libevent-2.1.8-stable版本匹配的openssl版本為1.1版本系列,因此去掉其他openssl版本,保留openssl1.1版本,再編譯libevent-2.1.8-stable。
? ? 然后在工程文件里引入編譯好的libevent庫,及其openssl庫:
? ? 再次編譯運行的時候,發現整個世界清凈了,可以正常代理播放了: