quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

version.c (17592B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  * SPDX-License-Identifier: curl
     22  *
     23  ***************************************************************************/
     24 
     25 #include "curl_setup.h"
     26 
     27 #ifdef USE_NGHTTP2
     28 #include <nghttp2/nghttp2.h>
     29 #endif
     30 
     31 #include <curl/curl.h>
     32 #include "urldata.h"
     33 #include "vtls/vtls.h"
     34 #include "http2.h"
     35 #include "vssh/ssh.h"
     36 #include "vquic/vquic.h"
     37 #include "curl_printf.h"
     38 #include "easy_lock.h"
     39 
     40 #ifdef USE_ARES
     41 #  include <ares.h>
     42 #endif
     43 
     44 #ifdef USE_LIBIDN2
     45 #include <idn2.h>
     46 #endif
     47 
     48 #ifdef USE_LIBPSL
     49 #include <libpsl.h>
     50 #endif
     51 
     52 #ifdef USE_LIBRTMP
     53 #include <librtmp/rtmp.h>
     54 #include "curl_rtmp.h"
     55 #endif
     56 
     57 #ifdef HAVE_LIBZ
     58 #include <zlib.h>
     59 #endif
     60 
     61 #ifdef HAVE_BROTLI
     62 #if defined(__GNUC__) || defined(__clang__)
     63 /* Ignore -Wvla warnings in brotli headers */
     64 #pragma GCC diagnostic push
     65 #pragma GCC diagnostic ignored "-Wvla"
     66 #endif
     67 #include <brotli/decode.h>
     68 #if defined(__GNUC__) || defined(__clang__)
     69 #pragma GCC diagnostic pop
     70 #endif
     71 #endif
     72 
     73 #ifdef HAVE_ZSTD
     74 #include <zstd.h>
     75 #endif
     76 
     77 #ifdef USE_GSASL
     78 #include <gsasl.h>
     79 #endif
     80 
     81 #ifdef USE_OPENLDAP
     82 #include <ldap.h>
     83 #endif
     84 
     85 #ifdef HAVE_BROTLI
     86 static void brotli_version(char *buf, size_t bufsz)
     87 {
     88   uint32_t brotli_version = BrotliDecoderVersion();
     89   unsigned int major = brotli_version >> 24;
     90   unsigned int minor = (brotli_version & 0x00FFFFFF) >> 12;
     91   unsigned int patch = brotli_version & 0x00000FFF;
     92   (void)msnprintf(buf, bufsz, "brotli/%u.%u.%u", major, minor, patch);
     93 }
     94 #endif
     95 
     96 #ifdef HAVE_ZSTD
     97 static void zstd_version(char *buf, size_t bufsz)
     98 {
     99   unsigned int version = ZSTD_versionNumber();
    100   unsigned int major = version / (100 * 100);
    101   unsigned int minor = (version - (major * 100 * 100)) / 100;
    102   unsigned int patch = version - (major * 100 * 100) - (minor * 100);
    103   (void)msnprintf(buf, bufsz, "zstd/%u.%u.%u", major, minor, patch);
    104 }
    105 #endif
    106 
    107 #ifdef USE_OPENLDAP
    108 static void oldap_version(char *buf, size_t bufsz)
    109 {
    110   LDAPAPIInfo api;
    111   api.ldapai_info_version = LDAP_API_INFO_VERSION;
    112 
    113   if(ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) == LDAP_OPT_SUCCESS) {
    114     unsigned int patch = (unsigned int)(api.ldapai_vendor_version % 100);
    115     unsigned int major = (unsigned int)(api.ldapai_vendor_version / 10000);
    116     unsigned int minor =
    117       (((unsigned int)api.ldapai_vendor_version - major * 10000)
    118        - patch) / 100;
    119     msnprintf(buf, bufsz, "%s/%u.%u.%u",
    120               api.ldapai_vendor_name, major, minor, patch);
    121     ldap_memfree(api.ldapai_vendor_name);
    122     ber_memvfree((void **)api.ldapai_extensions);
    123   }
    124   else
    125     msnprintf(buf, bufsz, "OpenLDAP");
    126 }
    127 #endif
    128 
    129 #ifdef USE_LIBPSL
    130 static void psl_version(char *buf, size_t bufsz)
    131 {
    132 #if defined(PSL_VERSION_MAJOR) && (PSL_VERSION_MAJOR > 0 ||     \
    133                                    PSL_VERSION_MINOR >= 11)
    134   int num = psl_check_version_number(0);
    135   msnprintf(buf, bufsz, "libpsl/%d.%d.%d",
    136             num >> 16, (num >> 8) & 0xff, num & 0xff);
    137 #else
    138   msnprintf(buf, bufsz, "libpsl/%s", psl_get_version());
    139 #endif
    140 }
    141 #endif
    142 
    143 #if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
    144 #define USE_IDN
    145 #endif
    146 
    147 #ifdef USE_IDN
    148 static void idn_version(char *buf, size_t bufsz)
    149 {
    150 #ifdef USE_LIBIDN2
    151   msnprintf(buf, bufsz, "libidn2/%s", idn2_check_version(NULL));
    152 #elif defined(USE_WIN32_IDN)
    153   msnprintf(buf, bufsz, "WinIDN");
    154 #elif defined(USE_APPLE_IDN)
    155   msnprintf(buf, bufsz, "AppleIDN");
    156 #endif
    157 }
    158 #endif
    159 
    160 /*
    161  * curl_version() returns a pointer to a static buffer.
    162  *
    163  * It is implemented to work multi-threaded by making sure repeated invokes
    164  * generate the exact same string and never write any temporary data like
    165  * zeros in the data.
    166  */
    167 
    168 #define VERSION_PARTS 16 /* number of substrings we can concatenate */
    169 
    170 char *curl_version(void)
    171 {
    172   static char out[300];
    173   char *outp;
    174   size_t outlen;
    175   const char *src[VERSION_PARTS];
    176 #ifdef USE_SSL
    177   char ssl_version[200];
    178 #endif
    179 #ifdef HAVE_LIBZ
    180   char z_version[30];
    181 #endif
    182 #ifdef HAVE_BROTLI
    183   char br_version[30];
    184 #endif
    185 #ifdef HAVE_ZSTD
    186   char zstd_ver[30];
    187 #endif
    188 #ifdef USE_ARES
    189   char cares_version[30];
    190 #endif
    191 #ifdef USE_IDN
    192   char idn_ver[30];
    193 #endif
    194 #ifdef USE_LIBPSL
    195   char psl_ver[30];
    196 #endif
    197 #ifdef USE_SSH
    198   char ssh_version[30];
    199 #endif
    200 #ifdef USE_NGHTTP2
    201   char h2_version[30];
    202 #endif
    203 #ifdef USE_HTTP3
    204   char h3_version[30];
    205 #endif
    206 #ifdef USE_LIBRTMP
    207   char rtmp_version[30];
    208 #endif
    209 #ifdef USE_GSASL
    210   char gsasl_buf[30];
    211 #endif
    212 #ifdef USE_OPENLDAP
    213   char ldap_buf[30];
    214 #endif
    215   int i = 0;
    216   int j;
    217 
    218 #ifdef DEBUGBUILD
    219   /* Override version string when environment variable CURL_VERSION is set */
    220   const char *debugversion = getenv("CURL_VERSION");
    221   if(debugversion) {
    222     msnprintf(out, sizeof(out), "%s", debugversion);
    223     return out;
    224   }
    225 #endif
    226 
    227   src[i++] = LIBCURL_NAME "/" LIBCURL_VERSION;
    228 #ifdef USE_SSL
    229   Curl_ssl_version(ssl_version, sizeof(ssl_version));
    230   src[i++] = ssl_version;
    231 #endif
    232 #ifdef HAVE_LIBZ
    233   msnprintf(z_version, sizeof(z_version), "zlib/%s", zlibVersion());
    234   src[i++] = z_version;
    235 #endif
    236 #ifdef HAVE_BROTLI
    237   brotli_version(br_version, sizeof(br_version));
    238   src[i++] = br_version;
    239 #endif
    240 #ifdef HAVE_ZSTD
    241   zstd_version(zstd_ver, sizeof(zstd_ver));
    242   src[i++] = zstd_ver;
    243 #endif
    244 #ifdef USE_ARES
    245   msnprintf(cares_version, sizeof(cares_version),
    246             "c-ares/%s", ares_version(NULL));
    247   src[i++] = cares_version;
    248 #endif
    249 #ifdef USE_IDN
    250   idn_version(idn_ver, sizeof(idn_ver));
    251   src[i++] = idn_ver;
    252 #endif
    253 #ifdef USE_LIBPSL
    254   psl_version(psl_ver, sizeof(psl_ver));
    255   src[i++] = psl_ver;
    256 #endif
    257 #ifdef USE_SSH
    258   Curl_ssh_version(ssh_version, sizeof(ssh_version));
    259   src[i++] = ssh_version;
    260 #endif
    261 #ifdef USE_NGHTTP2
    262   Curl_http2_ver(h2_version, sizeof(h2_version));
    263   src[i++] = h2_version;
    264 #endif
    265 #ifdef USE_HTTP3
    266   Curl_quic_ver(h3_version, sizeof(h3_version));
    267   src[i++] = h3_version;
    268 #endif
    269 #ifdef USE_LIBRTMP
    270   Curl_rtmp_version(rtmp_version, sizeof(rtmp_version));
    271   src[i++] = rtmp_version;
    272 #endif
    273 #ifdef USE_GSASL
    274   msnprintf(gsasl_buf, sizeof(gsasl_buf), "libgsasl/%s",
    275             gsasl_check_version(NULL));
    276   src[i++] = gsasl_buf;
    277 #endif
    278 #ifdef USE_OPENLDAP
    279   oldap_version(ldap_buf, sizeof(ldap_buf));
    280   src[i++] = ldap_buf;
    281 #endif
    282 
    283   DEBUGASSERT(i <= VERSION_PARTS);
    284 
    285   outp = &out[0];
    286   outlen = sizeof(out);
    287   for(j = 0; j < i; j++) {
    288     size_t n = strlen(src[j]);
    289     /* we need room for a space, the string and the final zero */
    290     if(outlen <= (n + 2))
    291       break;
    292     if(j) {
    293       /* prepend a space if not the first */
    294       *outp++ = ' ';
    295       outlen--;
    296     }
    297     memcpy(outp, src[j], n);
    298     outp += n;
    299     outlen -= n;
    300   }
    301   *outp = 0;
    302 
    303   return out;
    304 }
    305 
    306 /* data for curl_version_info
    307 
    308    Keep the list sorted alphabetically. It is also written so that each
    309    protocol line has its own #if line to make things easier on the eye.
    310  */
    311 
    312 static const char * const supported_protocols[] = {
    313 #ifndef CURL_DISABLE_DICT
    314   "dict",
    315 #endif
    316 #ifndef CURL_DISABLE_FILE
    317   "file",
    318 #endif
    319 #ifndef CURL_DISABLE_FTP
    320   "ftp",
    321 #endif
    322 #if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
    323   "ftps",
    324 #endif
    325 #ifndef CURL_DISABLE_GOPHER
    326   "gopher",
    327 #endif
    328 #if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER)
    329   "gophers",
    330 #endif
    331 #ifndef CURL_DISABLE_HTTP
    332   "http",
    333 #endif
    334 #if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
    335   "https",
    336 #endif
    337 #ifndef CURL_DISABLE_IMAP
    338   "imap",
    339 #endif
    340 #if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP)
    341   "imaps",
    342 #endif
    343 #ifndef CURL_DISABLE_LDAP
    344   "ldap",
    345 #if !defined(CURL_DISABLE_LDAPS) && \
    346     ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
    347      (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
    348   "ldaps",
    349 #endif
    350 #endif
    351 #ifndef CURL_DISABLE_MQTT
    352   "mqtt",
    353 #endif
    354 #ifndef CURL_DISABLE_POP3
    355   "pop3",
    356 #endif
    357 #if defined(USE_SSL) && !defined(CURL_DISABLE_POP3)
    358   "pop3s",
    359 #endif
    360 #ifdef USE_LIBRTMP
    361   "rtmp",
    362   "rtmpe",
    363   "rtmps",
    364   "rtmpt",
    365   "rtmpte",
    366   "rtmpts",
    367 #endif
    368 #ifndef CURL_DISABLE_RTSP
    369   "rtsp",
    370 #endif
    371 #if defined(USE_SSH) && !defined(USE_WOLFSSH)
    372   "scp",
    373 #endif
    374 #ifdef USE_SSH
    375   "sftp",
    376 #endif
    377 #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE)
    378   "smb",
    379 #  ifdef USE_SSL
    380   "smbs",
    381 #  endif
    382 #endif
    383 #ifndef CURL_DISABLE_SMTP
    384   "smtp",
    385 #endif
    386 #if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP)
    387   "smtps",
    388 #endif
    389 #ifndef CURL_DISABLE_TELNET
    390   "telnet",
    391 #endif
    392 #ifndef CURL_DISABLE_TFTP
    393   "tftp",
    394 #endif
    395 #ifndef CURL_DISABLE_HTTP
    396   /* WebSocket support relies on HTTP */
    397 #ifndef CURL_DISABLE_WEBSOCKETS
    398   "ws",
    399 #endif
    400 #if defined(USE_SSL) && !defined(CURL_DISABLE_WEBSOCKETS)
    401   "wss",
    402 #endif
    403 #endif
    404 
    405   NULL
    406 };
    407 
    408 /*
    409  * Feature presence runtime check functions.
    410  *
    411  * Warning: the value returned by these should not change between
    412  * curl_global_init() and curl_global_cleanup() calls.
    413  */
    414 
    415 #if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
    416 static int idn_present(curl_version_info_data *info)
    417 {
    418 #if defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
    419   (void)info;
    420   return TRUE;
    421 #else
    422   return info->libidn != NULL;
    423 #endif
    424 }
    425 #endif
    426 
    427 #if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY) && \
    428   !defined(CURL_DISABLE_HTTP)
    429 static int https_proxy_present(curl_version_info_data *info)
    430 {
    431   (void) info;
    432   return Curl_ssl_supports(NULL, SSLSUPP_HTTPS_PROXY);
    433 }
    434 #endif
    435 
    436 #if defined(USE_SSL) && defined(USE_ECH)
    437 static int ech_present(curl_version_info_data *info)
    438 {
    439   (void) info;
    440   return Curl_ssl_supports(NULL, SSLSUPP_ECH);
    441 }
    442 #endif
    443 
    444 /*
    445  * Features table.
    446  *
    447  * Keep the features alphabetically sorted.
    448  * Use FEATURE() macro to define an entry: this allows documentation check.
    449  */
    450 
    451 #define FEATURE(name, present, bitmask) {(name), (present), (bitmask)}
    452 
    453 struct feat {
    454   const char *name;
    455   int        (*present)(curl_version_info_data *info);
    456   int        bitmask;
    457 };
    458 
    459 static const struct feat features_table[] = {
    460 #ifndef CURL_DISABLE_ALTSVC
    461   FEATURE("alt-svc",     NULL,                CURL_VERSION_ALTSVC),
    462 #endif
    463 #if defined(USE_ARES) && defined(CURLRES_THREADED) && defined(USE_HTTPSRR)
    464   FEATURE("asyn-rr", NULL,             0),
    465 #endif
    466 #ifdef CURLRES_ASYNCH
    467   FEATURE("AsynchDNS",   NULL,                CURL_VERSION_ASYNCHDNS),
    468 #endif
    469 #ifdef HAVE_BROTLI
    470   FEATURE("brotli",      NULL,                CURL_VERSION_BROTLI),
    471 #endif
    472 #ifdef DEBUGBUILD
    473   FEATURE("Debug",       NULL,                CURL_VERSION_DEBUG),
    474 #endif
    475 #if defined(USE_SSL) && defined(USE_ECH)
    476   FEATURE("ECH",         ech_present,         0),
    477 
    478 #ifndef USE_HTTPSRR
    479 #error "ECH enabled but not HTTPSRR, must be a config error"
    480 #endif
    481 #endif
    482 #ifdef USE_GSASL
    483   FEATURE("gsasl",       NULL,                CURL_VERSION_GSASL),
    484 #endif
    485 #ifdef HAVE_GSSAPI
    486   FEATURE("GSS-API",     NULL,                CURL_VERSION_GSSAPI),
    487 #endif
    488 #ifndef CURL_DISABLE_HSTS
    489   FEATURE("HSTS",        NULL,                CURL_VERSION_HSTS),
    490 #endif
    491 #if defined(USE_NGHTTP2)
    492   FEATURE("HTTP2",       NULL,                CURL_VERSION_HTTP2),
    493 #endif
    494 #if defined(USE_HTTP3)
    495   FEATURE("HTTP3",       NULL,                CURL_VERSION_HTTP3),
    496 #endif
    497 #if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY) && \
    498   !defined(CURL_DISABLE_HTTP)
    499   FEATURE("HTTPS-proxy", https_proxy_present, CURL_VERSION_HTTPS_PROXY),
    500 #endif
    501 #if defined(USE_HTTPSRR)
    502   FEATURE("HTTPSRR",     NULL,                0),
    503 #endif
    504 #if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
    505   FEATURE("IDN",         idn_present,         CURL_VERSION_IDN),
    506 #endif
    507 #ifdef USE_IPV6
    508   FEATURE("IPv6",        NULL,                CURL_VERSION_IPV6),
    509 #endif
    510 #ifdef USE_KERBEROS5
    511   FEATURE("Kerberos",    NULL,                CURL_VERSION_KERBEROS5),
    512 #endif
    513 #if (SIZEOF_CURL_OFF_T > 4) && \
    514     ( (SIZEOF_OFF_T > 4) || defined(USE_WIN32_LARGE_FILES) )
    515   FEATURE("Largefile",   NULL,                CURL_VERSION_LARGEFILE),
    516 #endif
    517 #ifdef HAVE_LIBZ
    518   FEATURE("libz",        NULL,                CURL_VERSION_LIBZ),
    519 #endif
    520 #ifdef CURL_WITH_MULTI_SSL
    521   FEATURE("MultiSSL",    NULL,                CURL_VERSION_MULTI_SSL),
    522 #endif
    523 #ifdef USE_NTLM
    524   FEATURE("NTLM",        NULL,                CURL_VERSION_NTLM),
    525 #endif
    526 #if defined(USE_LIBPSL)
    527   FEATURE("PSL",         NULL,                CURL_VERSION_PSL),
    528 #endif
    529 #ifdef USE_SPNEGO
    530   FEATURE("SPNEGO",      NULL,                CURL_VERSION_SPNEGO),
    531 #endif
    532 #ifdef USE_SSL
    533   FEATURE("SSL",         NULL,                CURL_VERSION_SSL),
    534 #endif
    535 #if defined(USE_SSLS_EXPORT)
    536   FEATURE("SSLS-EXPORT", NULL,                0),
    537 #endif
    538 #ifdef USE_WINDOWS_SSPI
    539   FEATURE("SSPI",        NULL,                CURL_VERSION_SSPI),
    540 #endif
    541 #ifdef GLOBAL_INIT_IS_THREADSAFE
    542   FEATURE("threadsafe",  NULL,                CURL_VERSION_THREADSAFE),
    543 #endif
    544 #ifdef USE_TLS_SRP
    545   FEATURE("TLS-SRP",     NULL,                CURL_VERSION_TLSAUTH_SRP),
    546 #endif
    547 #ifdef CURLDEBUG
    548   FEATURE("TrackMemory", NULL,                CURL_VERSION_CURLDEBUG),
    549 #endif
    550 #if defined(_WIN32) && defined(UNICODE) && defined(_UNICODE)
    551   FEATURE("Unicode",     NULL,                CURL_VERSION_UNICODE),
    552 #endif
    553 #ifdef USE_UNIX_SOCKETS
    554   FEATURE("UnixSockets", NULL,                CURL_VERSION_UNIX_SOCKETS),
    555 #endif
    556 #ifdef HAVE_ZSTD
    557   FEATURE("zstd",        NULL,                CURL_VERSION_ZSTD),
    558 #endif
    559   {NULL,                 NULL,                0}
    560 };
    561 
    562 static const char *feature_names[sizeof(features_table) /
    563                                  sizeof(features_table[0])] = {NULL};
    564 
    565 
    566 static curl_version_info_data version_info = {
    567   CURLVERSION_NOW,
    568   LIBCURL_VERSION,
    569   LIBCURL_VERSION_NUM,
    570   CURL_OS, /* as found by configure or set by hand at build-time */
    571   0,    /* features bitmask is built at runtime */
    572   NULL, /* ssl_version */
    573   0,    /* ssl_version_num, this is kept at zero */
    574   NULL, /* zlib_version */
    575   supported_protocols,
    576   NULL, /* c-ares version */
    577   0,    /* c-ares version numerical */
    578   NULL, /* libidn version */
    579   0,    /* iconv version */
    580   NULL, /* ssh lib version */
    581   0,    /* brotli_ver_num */
    582   NULL, /* brotli version */
    583   0,    /* nghttp2 version number */
    584   NULL, /* nghttp2 version string */
    585   NULL, /* quic library string */
    586 #ifdef CURL_CA_BUNDLE
    587   CURL_CA_BUNDLE, /* cainfo */
    588 #else
    589   NULL,
    590 #endif
    591 #ifdef CURL_CA_PATH
    592   CURL_CA_PATH,  /* capath */
    593 #else
    594   NULL,
    595 #endif
    596   0,    /* zstd_ver_num */
    597   NULL, /* zstd version */
    598   NULL, /* Hyper version */
    599   NULL, /* gsasl version */
    600   feature_names,
    601   NULL  /* rtmp version */
    602 };
    603 
    604 curl_version_info_data *curl_version_info(CURLversion stamp)
    605 {
    606   size_t n;
    607   const struct feat *p;
    608   int features = 0;
    609 
    610 #if defined(USE_SSH)
    611   static char ssh_buf[80];  /* 'ssh_buffer' clashes with libssh/libssh.h */
    612 #endif
    613 #ifdef USE_SSL
    614 #ifdef CURL_WITH_MULTI_SSL
    615   static char ssl_buffer[200];
    616 #else
    617   static char ssl_buffer[80];
    618 #endif
    619 #endif
    620 #ifdef HAVE_BROTLI
    621   static char brotli_buffer[80];
    622 #endif
    623 #ifdef HAVE_ZSTD
    624   static char zstd_buffer[80];
    625 #endif
    626 
    627   (void)stamp; /* avoid compiler warnings, we do not use this */
    628 
    629 #ifdef USE_SSL
    630   Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer));
    631   version_info.ssl_version = ssl_buffer;
    632 #endif
    633 
    634 #ifdef HAVE_LIBZ
    635   version_info.libz_version = zlibVersion();
    636   /* libz left NULL if non-existing */
    637 #endif
    638 #ifdef USE_ARES
    639   {
    640     int aresnum;
    641     version_info.ares = ares_version(&aresnum);
    642     version_info.ares_num = aresnum;
    643   }
    644 #endif
    645 #ifdef USE_LIBIDN2
    646   /* This returns a version string if we use the given version or later,
    647      otherwise it returns NULL */
    648   version_info.libidn = idn2_check_version(IDN2_VERSION);
    649 #endif
    650 
    651 #if defined(USE_SSH)
    652   Curl_ssh_version(ssh_buf, sizeof(ssh_buf));
    653   version_info.libssh_version = ssh_buf;
    654 #endif
    655 
    656 #ifdef HAVE_BROTLI
    657   version_info.brotli_ver_num = BrotliDecoderVersion();
    658   brotli_version(brotli_buffer, sizeof(brotli_buffer));
    659   version_info.brotli_version = brotli_buffer;
    660 #endif
    661 
    662 #ifdef HAVE_ZSTD
    663   version_info.zstd_ver_num = (unsigned int)ZSTD_versionNumber();
    664   zstd_version(zstd_buffer, sizeof(zstd_buffer));
    665   version_info.zstd_version = zstd_buffer;
    666 #endif
    667 
    668 #ifdef USE_NGHTTP2
    669   {
    670     nghttp2_info *h2 = nghttp2_version(0);
    671     version_info.nghttp2_ver_num = (unsigned int)h2->version_num;
    672     version_info.nghttp2_version = h2->version_str;
    673   }
    674 #endif
    675 
    676 #ifdef USE_HTTP3
    677   {
    678     static char quicbuffer[80];
    679     Curl_quic_ver(quicbuffer, sizeof(quicbuffer));
    680     version_info.quic_version = quicbuffer;
    681   }
    682 #endif
    683 
    684 #ifdef USE_GSASL
    685   {
    686     version_info.gsasl_version = gsasl_check_version(NULL);
    687   }
    688 #endif
    689 
    690   /* Get available features, build bitmask and names array. */
    691   n = 0;
    692   for(p = features_table; p->name; p++)
    693     if(!p->present || p->present(&version_info)) {
    694       features |= p->bitmask;
    695       feature_names[n++] = p->name;
    696     }
    697 
    698   feature_names[n] = NULL;  /* Terminate array. */
    699   version_info.features = features;
    700 
    701 #ifdef USE_LIBRTMP
    702   {
    703     static char rtmp_version[30];
    704     Curl_rtmp_version(rtmp_version, sizeof(rtmp_version));
    705     version_info.rtmp_version = rtmp_version;
    706   }
    707 #endif
    708 
    709   return &version_info;
    710 }