欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

libcurl:Protocol "smtps" not supported or disabled in libcurl

程序员文章站 2022-06-12 19:50:25
...

libcurl:Protocol “smtps” not supported or disabled in libcurl

在使用libcurl来作为MUA时,开启DEBUG模式,使用smtps协议,在运行时报错:

libcurl:Protocol “smtps” not supported or disabled in libcurl

原因在于,安装libcurl时没有带着openssl。

安装包:curl-7.56.1.tar.gz

错误安装:

[jiang@localhost curl-7.56.1]$ ./configure --prefix=$HOME/libcurl
checking whether to enable maintainer-specific portions of Makefiles... no
……
configure: WARNING: SSL disabled, you will not be able to use HTTPS, FTPS, NTLM and more.
configure: WARNING: Use --with-ssl, --with-gnutls, --with-polarssl, --with-cyassl, --with-nss, --with-axtls, --with-winssl, or --with-darwinssl to address this.
……
configure: Configured to build curl/libcurl:

  curl version:     7.56.1
  Host setup:       x86_64-pc-linux-gnu
  Install prefix:   /home/jiang/libcurl
  Compiler:         gcc
  SSL support:      no      (--with-{ssl,gnutls,nss,polarssl,mbedtls,cyassl,axtls,winssl,darwinssl} )
  SSH support:      no      (--with-libssh2)
  zlib support:     no      (--with-zlib)
  GSS-API support:  no      (--with-gssapi)
  TLS-SRP support:  no      (--enable-tls-srp)
  resolver:         POSIX threaded
  IPv6 support:     enabled
  Unix sockets support: enabled
  IDN support:      no      (--with-{libidn2,winidn})
  Build libcurl:    Shared=yes, Static=yes
  Built-in manual:  enabled
  --libcurl option: enabled (--disable-libcurl-option)
  Verbose errors:   enabled (--disable-verbose)
  SSPI support:     no      (--enable-sspi)
  ca cert bundle:   /etc/pki/tls/certs/ca-bundle.crt
  ca cert path:     no
  ca fallback:      no
  LDAP support:     no      (--enable-ldap / --with-ldap-lib / --with-lber-lib)
  LDAPS support:    no      (--enable-ldaps)
  RTSP support:     enabled
  RTMP support:     no      (--with-librtmp)
  metalink support: no      (--with-libmetalink)
  PSL support:      no      (libpsl not found)
  HTTP2 support:    disabled (--with-nghttp2)
  Protocols:        DICT FILE FTP GOPHER HTTP IMAP POP3 RTSP SMTP TELNET TFTP

通常在./configure生成makefile这一步,我都基本不看,能生成makefile即可,然后直接编译安装。

ATTENTION:实际应该仔细确认summary这一部分,可能存在一些潜在的运行时问题。

继续进行编译安装:

[jiang@localhost curl-7.56.1]$ make && make install

OK,到此libcurl就安装完毕。

Code:

#include <stdio.h>
#include <string.h>
#include <curl/curl.h>

#define FROM_ADDR    "<[email protected]>"
#define TO_ADDR      "<[email protected]>"

#define FROM_MAIL "[email protected]" FROM_ADDR
#define TO_MAIL   "[email protected]" TO_ADDR

static const char *payload_text[] = {
  "To: " TO_MAIL "\r\n",
  "From: " FROM_MAIL "\r\n",
  "Subject: SMTP example message\r\n",
  "\r\n", /* empty line to divide headers from body, see RFC5322 */
  "The body of the message starts here.\r\n",
  "\r\n",
  "It could be a lot of lines, could be MIME encoded, whatever.\r\n",
  "Check RFC5322.\r\n",
  NULL
};

struct upload_status {
  int lines_read;
};

static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp)
{
  struct upload_status *upload_ctx = (struct upload_status *)userp;
  const char *data;

  if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) {
    return 0;
  }

  data = payload_text[upload_ctx->lines_read];

  if(data) {
    size_t len = strlen(data);
    memcpy(ptr, data, len);
    upload_ctx->lines_read++;

    return len;
  }

  return 0;
}

int main(void)
{
  CURL *curl;
  CURLcode res = CURLE_OK;
  struct curl_slist *recipients = NULL;
  struct upload_status upload_ctx;

  upload_ctx.lines_read = 0;

  curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "smtps://smtp.qq.com:465");

    curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM_ADDR);

    recipients = curl_slist_append(recipients, TO_ADDR);
    curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);

    curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
    curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);

    curl_easy_setopt(curl, CURLOPT_USERNAME, "[email protected]");
    curl_easy_setopt(curl, CURLOPT_PASSWORD, "xxxxxxxxxxxxxxxx");

    curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);

    /* DEBUG */
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

    /* Send the message */
    res = curl_easy_perform(curl);

    /* Check for errors */
    if(res != CURLE_OK)
    fprintf(stderr, "curl_easy_perform() failed: %s\n",
        curl_easy_strerror(res));

    curl_slist_free_all(recipients);

    curl_easy_cleanup(curl);
  }

  return (int)res;
}

编译 && 执行:

[jiang@localhost ~]$ gcc -o ssl ssl.c -I/home/jiang/libcurl/include -L /home/jiang/libcurl/lib -lcurl
[jiang@localhost ~]$ ./ssl
* Protocol smtps not supported or disabled in libcurl
* Unsupported protocol
curl_easy_perform() failed: Unsupported protocol

仔细回头看看,想想。

libcurl如果使用smtps,即使用TLS/SSL,那必然涉及到加解密算法,谁来做这个工作呢?

刚刚似乎安装libcurl时没有带着openssl?

实际可能由于openssl版本和libcurl要求的openssl版本不一致或其他原因,导致./configure在生成libcurl的makefile时,并没有(发现)已存在的openssl库。

解决办法:

重新安装/升级openssl:

[root@localhost ~]# yum install openssl-devel -y

重新安装libcurl:

[jiang@localhost curl-7.56.1]$ ./configure --prefix=$HOME/libcurl
……
configure: Configured to build curl/libcurl:

  curl version:     7.56.1
  Host setup:       x86_64-pc-linux-gnu
  Install prefix:   /home/jiang/libcurl
  Compiler:         gcc
  SSL support:      enabled (OpenSSL)
  SSH support:      no      (--with-libssh2)
  zlib support:     enabled
  GSS-API support:  no      (--with-gssapi)
  TLS-SRP support:  no      (--enable-tls-srp)
  resolver:         POSIX threaded
  IPv6 support:     enabled
  Unix sockets support: enabled
  IDN support:      no      (--with-{libidn2,winidn})
  Build libcurl:    Shared=yes, Static=yes
  Built-in manual:  enabled
  --libcurl option: enabled (--disable-libcurl-option)
  Verbose errors:   enabled (--disable-verbose)
  SSPI support:     no      (--enable-sspi)
  ca cert bundle:   /etc/pki/tls/certs/ca-bundle.crt
  ca cert path:     no
  ca fallback:      no
  LDAP support:     no      (--enable-ldap / --with-ldap-lib / --with-lber-lib)
  LDAPS support:    no      (--enable-ldaps)
  RTSP support:     enabled
  RTMP support:     no      (--with-librtmp)
  metalink support: no      (--with-libmetalink)
  PSL support:      no      (libpsl not found)
  HTTP2 support:    disabled (--with-nghttp2)
  Protocols:        DICT FILE FTP FTPS GOPHER HTTP HTTPS IMAP IMAPS POP3 POP3S RTSP SMB SMBS SMTP SMTPS TELNET TFTP

[jiang@localhost curl-7.56.1]$ make && make install

仔细对比两次./configure生成输出的summary:

  Protocols:        DICT FILE FTP GOPHER HTTP IMAP POP3 RTSP SMTP TELNET TFTP
  Protocols:        DICT FILE FTP FTPS GOPHER HTTP HTTPS IMAP IMAPS POP3 POP3S RTSP SMB SMBS SMTP 

即,通过安装/升级openssl,使得在安装libcurl生成makefile时,让其发现openssl的存在,带着openssl编译安装,以支持所有需要TLS/SSL的协议(HTTPS、SMTPS等)。

代码编译&&执行如下:

[jiang@localhost ~]$ gcc -o ssl ssl.c -I/home/jiang/libcurl/include -L /home/jiang/libcurl/lib -lcurl
[jiang@localhost ~]$ ./ssl
* Rebuilt URL to: smtps://smtp.qq.com:465/
*   Trying 14.17.57.241...
* TCP_NODELAY set
* Connected to smtp.qq.com (14.17.57.241) port 465 (#0)
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* SSL connection using TLSv1.2 / AES128-SHA256
* Server certificate:
*  subject: C=CN; ST=Guangdong; L=Shenzhen; O=Shenzhen Tencent Computer Systems Company Limited; OU=R&D; CN=pop.qq.com
*  start date: Sep  7 00:00:00 2016 GMT
*  expire date: Dec  7 23:59:59 2018 GMT
*  issuer: C=US; O=GeoTrust Inc.; CN=GeoTrust SSL CA - G3
*  SSL certificate verify ok.
< 220 smtp.qq.com Esmtp QQ Mail Server
> EHLO localhost
< 250-smtp.qq.com
< 250-PIPELINING
< 250-SIZE 73400320
< 250-AUTH LOGIN PLAIN
< 250-AUTH=LOGIN
< 250-MAILCOMPRESS
< 250 8BITMIME
> AUTH LOGIN
< 334 VXNlcm5hbWU6
> MTE1ODgwMTQxMUBxcS5jb20=
< 334 UGFzc3dvcmQ6
> YmJ1eXVwZnphdmFoaGhpYw==
< 235 Authentication successful
> MAIL FROM:<[email protected]>
< 250 Ok
> RCPT TO:<[email protected]>
< 250 Ok
> DATA
< 354 End data with <CR><LF>.<CR><LF>
< 250 Ok: queued as 
* Connection #0 to host smtp.qq.com left intact

OK,发送成功(TLS/SSL)。

还有一种可能,也会导致上面的错误信息:

可执行文件链接的动态库不是新版的,支持SMTPS的动态库,而是旧版本的libcurl动态库。

[jiang@localhost ~]$ ldd ./ssl
    linux-vdso.so.1 =>  (0x00007ffc6cbeb000)
    libcurl.so.4 => /usr/lib64/libcurl.so.4 (0x000000312ec00000)
    ……
[jiang@localhost ~]$ ./ssl
* Protocol smtps not supported or disabled in libcurl
* Unsupported protocol
curl_easy_perform() failed: Unsupported protocol

通过设置LD_LIBRARY_PATH,使其找到正确的libcurl动态库(当然,也存在很多其他方法啦):

[[email protected] ~]$ export LD_LIBRARY_PATH=$HOME/libcurl/lib:$LD_LIBRARY_PATH
[[email protected] ~]$ ./ssl
* Rebuilt URL to: smtps://smtp.qq.com:465/
*   Trying 14.17.57.241...
* TCP_NODELAY set
* Connected to smtp.qq.com (14.17.57.241) port 465 (#0)
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
……

总结:

有两种原因导致:

Protocol “smtps” not supported or disabled in libcurl

1.在./configure生成libcurl的makefile时,可能由于openssl库安装不正确、版本等问题导致configure找不到openssl库
2.执行可执行文件时,动态链接器ld找到的不是正确的,支持TLS/SSL的libcurl,而是其他版本、不支持TLS/SSL的libcurl

同理,可能存在:

Protocol “https” not supported or disabled in libcurl

当运行时发现这个问题,可以先检查下libcurl是否支持openssl?安装libcurl时是否是带着openssl进行编译的?