diff --git a/.github/scripts/zephyr-4.x/builds.txt b/.github/scripts/zephyr-4.x/builds.txt index ea987610af9..b1316f7b98c 100644 --- a/.github/scripts/zephyr-4.x/builds.txt +++ b/.github/scripts/zephyr-4.x/builds.txt @@ -3,6 +3,7 @@ native_sim samples/wolfssl_tls_sock native_sim samples/wolfssl_tls_sock external_libc.conf native_sim samples/wolfssl_tls_sock tls_cert.conf +native_sim samples/wolfssl_tls_sock ocsp.conf native_sim samples/wolfssl_test native_sim samples/wolfssl_test external_libc.conf native_sim samples/wolfssl_benchmark diff --git a/.github/scripts/zephyr-4.x/ocsp.conf b/.github/scripts/zephyr-4.x/ocsp.conf new file mode 100644 index 00000000000..beda6b3dce3 --- /dev/null +++ b/.github/scripts/zephyr-4.x/ocsp.conf @@ -0,0 +1,3 @@ +# OCSP and stapling +CONFIG_WOLFSSL_OCSP=y +CONFIG_WOLFSSL_OCSP_STAPLING=y diff --git a/doc/dox_comments/header_files-ja/ssl.h b/doc/dox_comments/header_files-ja/ssl.h index b8398d1c9bc..2b1e139f362 100644 --- a/doc/dox_comments/header_files-ja/ssl.h +++ b/doc/dox_comments/header_files-ja/ssl.h @@ -4869,6 +4869,8 @@ int wolfSSL_set_tlsext_status_ocsp_resp_multi(WOLFSSL* ssl, unsigned char *resp, \brief OCSPステータスレスポンスを検証するコールバックを設定します。 + クライアントは処理するステープルOCSPレスポンスごとに、デコードできないものも含めてこのコールバックを呼び出します。クライアント証明書を検証するTLS 1.3サーバーも同様です。errにはライブラリの判定結果(0または負のエラーコード)が渡されます。証明書チェーンの処理は最初に失敗したレスポンスで停止するため、それ以降のレスポンスは渡されません。戻り値がerrを置き換えます。0はレスポンスを受け入れ、負の値はハンドシェイクを失敗させ、正の値はBAD_CERTIFICATE_STATUS_ERRORとして扱われます。 + OCSP検証中にピアの証明書チェーンにアクセスできるようにするため、SESSION_CERTSを有効にすることを推奨します。 \param ctx WOLFSSL_CTXオブジェクト。 diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index 5884a417171..195f9cddf06 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -6611,6 +6611,15 @@ int wolfSSL_set_tlsext_status_ocsp_resp_multi(WOLFSSL* ssl, unsigned char *resp, \brief Sets a callback to verify the OCSP status response. + The client calls it for each stapled OCSP response it processes, as does a + TLS 1.3 server checking the client's certificate, including a response + that does not decode. err holds the library's result (0 or a negative + error code). Processing of a certificate chain stops at the first + response that fails, so later responses are not passed to it. The return + value replaces err: 0 accepts the response, a negative value fails the + handshake, and a positive value is treated as + BAD_CERTIFICATE_STATUS_ERROR. + It is recommended to enable SESSION_CERTS in order to have access to the peer's certificate chain during OCSP verification. diff --git a/src/internal.c b/src/internal.c index 0c54d776a0d..5e272f29609 100644 --- a/src/internal.c +++ b/src/internal.c @@ -16596,7 +16596,6 @@ int CsrDoChainFallbackLookup(WOLFSSL* ssl, OcspRequest* request, int idx) (defined(HAVE_OCSP) && defined(WOLFSSL_TLS13) && \ defined(HAVE_CERTIFICATE_STATUS_REQUEST))) #if !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) -#ifndef NO_WOLFSSL_SERVER static int CsrDoStatusVerifyCb(WOLFSSL* ssl, byte* input, word32 inputSz, word32 idx, int ret) { @@ -16619,7 +16618,6 @@ static int CsrDoStatusVerifyCb(WOLFSSL* ssl, byte* input, word32 inputSz, word32 } return ret; } -#endif /* !NO_WOLFSSL_SERVER */ /* Parses one certificate_status message. TLS 1.3 reads the per-certificate * entries of the chain through this, so it is not tied to TLS 1.2. */ @@ -16703,8 +16701,10 @@ static int ProcessCSR_ex(WOLFSSL* ssl, byte* input, word32* inOutIdx, ssl->heap); /* Extract producedDate */ - if (OcspResponseDecode(response, SSL_CM(ssl), ssl->heap, 1, 1) != 0) + if (OcspResponseDecode(response, SSL_CM(ssl), ssl->heap, 1, 1) != 0) { + ssl->ocspProducedDateFormat = 0; ret = BAD_CERTIFICATE_STATUS_ERROR; + } if (ret == 0) { XMEMCPY(ssl->ocspProducedDate, response->producedDate, sizeof(ssl->ocspProducedDate)); @@ -16725,12 +16725,10 @@ static int ProcessCSR_ex(WOLFSSL* ssl, byte* input, word32* inOutIdx, ret = OCSP_CERT_REVOKED; else if (response->single->status->status != CERT_GOOD) ret = BAD_CERTIFICATE_STATUS_ERROR; - -#ifndef NO_WOLFSSL_SERVER - ret = CsrDoStatusVerifyCb(ssl, input + *inOutIdx, status_length, idx, ret); -#endif } + ret = CsrDoStatusVerifyCb(ssl, input + *inOutIdx, status_length, idx, ret); + *inOutIdx += status_length; /* FreeOcspResponse frees status and single only if @@ -20976,10 +20974,8 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx, /* only frees 'single' if single->isDynamic is set */ FreeOcspResponse(response); - #ifndef NO_WOLFSSL_SERVER ret = CsrDoStatusVerifyCb(ssl, input + *inOutIdx, status_length, idx, ret); - #endif if (ret == 0 && idx == 0) /* server cert must be OK */ endCertificateOK = 1; #if defined(HAVE_OCSP) && defined(WOLFSSL_NONBLOCK_OCSP) diff --git a/src/ssl_api_crl_ocsp.c b/src/ssl_api_crl_ocsp.c index e65e38a1db8..8afa84699c8 100644 --- a/src/ssl_api_crl_ocsp.c +++ b/src/ssl_api_crl_ocsp.c @@ -1289,7 +1289,6 @@ int wolfSSL_set_tlsext_status_ocsp_resp_multi(WOLFSSL* ssl, unsigned char *resp, return ret; } -#ifndef NO_WOLFSSL_SERVER /* Set the callback that verifies a stapled OCSP response. * * @param [in, out] ctx SSL/TLS context. @@ -1304,7 +1303,6 @@ void wolfSSL_CTX_set_ocsp_status_verify_cb(WOLFSSL_CTX* ctx, ctx->ocspStatusVerifyCbArg = cbArg; } } -#endif /* NO_WOLFSSL_SERVER */ #endif /* HAVE_CERTIFICATE_STATUS_REQUEST || * HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ diff --git a/tests/api.c b/tests/api.c index d03a32080f4..e510632bf24 100644 --- a/tests/api.c +++ b/tests/api.c @@ -47395,6 +47395,7 @@ TEST_CASE testCases[] = { TEST_DECL_GROUP("ocsp", test_ocsp_resp_times), TEST_DECL(test_ocsp_tls_cert_cb), TEST_DECL_GROUP("ocsp", test_ocsp_status_request_v2_multi_revoked_single), + TEST_DECL_GROUP("ocsp", test_ocsp_status_verify_cb_undecodable_staple), TEST_DECL_GROUP("ocsp", test_ocsp_cert_unknown_crl_fallback), TEST_DECL_GROUP("ocsp", test_ocsp_cert_unknown_crl_fallback_nonleaf), TEST_DECL_GROUP("ocsp", test_ocsp_no_url_policy), diff --git a/tests/api/test_ocsp.c b/tests/api/test_ocsp.c index c68f939df42..fbe6be01573 100644 --- a/tests/api/test_ocsp.c +++ b/tests/api/test_ocsp.c @@ -1973,11 +1973,165 @@ int test_ocsp_status_request_v2_multi_revoked_single(void) } #endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 && !WOLFSSL_NO_TLS12 */ +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST +/* A SEQUENCE header that claims more bytes than follow */ +static const byte test_ocsp_undecodable_staple_junk[] = { + 0x30, 0x05, 0x0a, 0x01, 0x00 +}; +static int test_ocsp_undecodable_staple_calls; +static int test_ocsp_undecodable_staple_err; +static word32 test_ocsp_undecodable_staple_idx; +static word32 test_ocsp_undecodable_staple_sz; + +static int test_ocsp_undecodable_staple_status_cb(WOLFSSL* ssl, void* ioCtx) +{ + byte* staple; + + (void)ioCtx; + staple = (byte*)XMALLOC(sizeof(test_ocsp_undecodable_staple_junk), NULL, + 0); + if (staple == NULL) + return WOLFSSL_OCSP_STATUS_CB_ALERT_FATAL; + XMEMCPY(staple, test_ocsp_undecodable_staple_junk, + sizeof(test_ocsp_undecodable_staple_junk)); + if (wolfSSL_set_tlsext_status_ocsp_resp_multi(ssl, staple, + sizeof(test_ocsp_undecodable_staple_junk), 0) != WOLFSSL_SUCCESS) { + XFREE(staple, NULL, 0); + return WOLFSSL_OCSP_STATUS_CB_ALERT_FATAL; + } + return WOLFSSL_OCSP_STATUS_CB_OK; +} + +static int test_ocsp_undecodable_staple_verify_cb(WOLFSSL* ssl, int err, + byte* staple, word32 stapleSz, word32 idx, void* arg) +{ + (void)ssl; + (void)staple; + test_ocsp_undecodable_staple_calls++; + test_ocsp_undecodable_staple_err = err; + test_ocsp_undecodable_staple_idx = idx; + test_ocsp_undecodable_staple_sz = stapleSz; + return (arg != NULL) ? 0 : err; +} + +/* + * The OCSP status verify callback sees a stapled response that does not + * decode, and can override the error like any other staple failure. + */ +int test_ocsp_status_verify_cb_undecodable_staple(void) +{ + EXPECT_DECLS; + size_t i; + int override; + WOLFSSL_ALERT_HISTORY h; +#ifndef NO_ASN_TIME + byte date[MAX_DATE_SIZE]; + int fmt = 0; +#endif + struct { + method_provider client_meth; + method_provider server_meth; + const char* tls_version; + } params[] = { +#if !defined(WOLFSSL_NO_TLS12) + { wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, "TLSv1_2" }, +#endif +#ifdef WOLFSSL_TLS13 + { wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLSv1_3" }, +#endif + }; + + for (i = 0; i < XELEM_CNT(params) && !EXPECT_FAIL(); i++) { + for (override = 0; override <= 1 && !EXPECT_FAIL(); override++) { + struct test_ssl_memio_ctx test_ctx; + + printf("\nTesting %s, %s\n", params[i].tls_version, + override ? "callback overrides" : "callback keeps error"); + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + test_ctx.c_cb.caPemFile = ""; + test_ctx.s_cb.certPemFile = ""; + test_ctx.s_cb.keyPemFile = ""; + test_ctx.c_cb.method = params[i].client_meth; + test_ctx.s_cb.method = params[i].server_meth; + test_ocsp_tls_cert_cb_opts.chainLen = 1; + test_ocsp_tls_cert_cb_opts.failStaple = 0; + test_ctx.s_cb.ctx_ready = test_ocsp_tls_cert_cb_ctx_ready; + + ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS); + ExpectIntEQ(wolfSSL_UnloadCertsKeys(test_ctx.s_ssl), + WOLFSSL_SUCCESS); + + ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(test_ctx.s_ctx), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_tlsext_status_cb(test_ctx.s_ctx, + test_ocsp_undecodable_staple_status_cb), WOLFSSL_SUCCESS); + + wolfSSL_set_verify(test_ctx.c_ssl, WOLFSSL_VERIFY_DEFAULT, + test_ocsp_tls_cert_cb_verify_cb); + wolfSSL_SetCertCbCtx(test_ctx.c_ssl, test_ctx.c_ssl); + wolfSSL_CTX_set_ocsp_status_verify_cb(test_ctx.c_ctx, + test_ocsp_undecodable_staple_verify_cb, + override ? &test_ctx : NULL); + ExpectIntEQ(wolfSSL_CTX_EnableOCSPStapling(test_ctx.c_ctx), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseOCSPStapling(test_ctx.c_ssl, + WOLFSSL_CSR_OCSP, 0), WOLFSSL_SUCCESS); + + #ifndef NO_ASN_TIME + /* Stale date from an earlier staple */ + if (test_ctx.c_ssl != NULL) { + XSTRNCPY((char*)test_ctx.c_ssl->ocspProducedDate, + "260101000000Z", + sizeof(test_ctx.c_ssl->ocspProducedDate)); + test_ctx.c_ssl->ocspProducedDateFormat = ASN_UTC_TIME; + } + #endif + + test_ocsp_undecodable_staple_calls = 0; + test_ocsp_undecodable_staple_err = 0; + test_ocsp_undecodable_staple_idx = 1; + test_ocsp_undecodable_staple_sz = 0; + ExpectIntEQ(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), + override ? TEST_SUCCESS : TEST_FAIL); + ExpectIntEQ(test_ocsp_undecodable_staple_calls, 1); + ExpectIntEQ(test_ocsp_undecodable_staple_err, + WC_NO_ERR_TRACE(BAD_CERTIFICATE_STATUS_ERROR)); + ExpectIntEQ(test_ocsp_undecodable_staple_idx, 0); + ExpectIntEQ(test_ocsp_undecodable_staple_sz, + sizeof(test_ocsp_undecodable_staple_junk)); + if (!override) { + ExpectIntEQ(wolfSSL_get_alert_history(test_ctx.s_ssl, &h), + WOLFSSL_SUCCESS); + ExpectIntEQ(h.last_rx.level, alert_fatal); + ExpectIntEQ(h.last_rx.code, bad_certificate_status_response); + } + #ifndef NO_ASN_TIME + ExpectIntEQ(wolfSSL_get_ocsp_producedDate(test_ctx.c_ssl, date, + sizeof(date), &fmt), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + #endif + + test_ssl_memio_cleanup(&test_ctx); + } + } + return EXPECT_RESULT(); +} +#else +int test_ocsp_status_verify_cb_undecodable_staple(void) +{ + return TEST_SKIPPED; +} +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ + #else /* feature guards */ int test_ocsp_tls_cert_cb(void) { return TEST_SKIPPED; } +int test_ocsp_status_verify_cb_undecodable_staple(void) +{ + return TEST_SKIPPED; +} int test_ocsp_status_request_v2_multi_revoked_single(void) { return TEST_SKIPPED; diff --git a/tests/api/test_ocsp.h b/tests/api/test_ocsp.h index 43431890751..0c0c6eb2d27 100644 --- a/tests/api/test_ocsp.h +++ b/tests/api/test_ocsp.h @@ -37,6 +37,7 @@ int test_ocsp_responder_keyhash_binding(void); int test_ocsp_response_parsing(void); int test_ocsp_tls_cert_cb(void); int test_ocsp_status_request_v2_multi_revoked_single(void); +int test_ocsp_status_verify_cb_undecodable_staple(void); int test_ocsp_cert_unknown_crl_fallback(void); int test_ocsp_cert_unknown_crl_fallback_nonleaf(void); int test_ocsp_no_url_policy(void); diff --git a/tests/api/test_ssl_crl_ocsp.c b/tests/api/test_ssl_crl_ocsp.c index eefae57313f..3bdf6dae3ea 100644 --- a/tests/api/test_ssl_crl_ocsp.c +++ b/tests/api/test_ssl_crl_ocsp.c @@ -257,6 +257,49 @@ int test_wolfSSL_CTX_tlsext_status_cb(void) return EXPECT_RESULT(); } +#if (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ + defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) && \ + !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) +static int test_ssl_crl_ocsp_verify_cb(WOLFSSL* ssl, int err, byte* resp, + word32 respSz, word32 idx, void* arg) +{ + (void)ssl; + (void)resp; + (void)respSz; + (void)idx; + (void)arg; + return err; +} +#endif + +/* Test setting the OCSP status verify callback on a client CTX. + * + * @return TEST_SUCCESS on success. + */ +int test_wolfSSL_CTX_set_ocsp_status_verify_cb(void) +{ + EXPECT_DECLS; +#if (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ + defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) && \ + !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + int arg = 0; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + wolfSSL_CTX_set_ocsp_status_verify_cb(ctx, test_ssl_crl_ocsp_verify_cb, + &arg); + ExpectTrue((ctx != NULL) && + (ctx->ocspStatusVerifyCb == test_ssl_crl_ocsp_verify_cb)); + ExpectTrue((ctx != NULL) && (ctx->ocspStatusVerifyCbArg == &arg)); + + wolfSSL_CTX_set_ocsp_status_verify_cb(ctx, NULL, NULL); + ExpectTrue((ctx != NULL) && (ctx->ocspStatusVerifyCb == NULL)); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + /* Test storing and retrieving a stapled OCSP response. * * @return TEST_SUCCESS on success. diff --git a/tests/api/test_ssl_crl_ocsp.h b/tests/api/test_ssl_crl_ocsp.h index d3cbbb4d6b7..cc3abc449b2 100644 --- a/tests/api/test_ssl_crl_ocsp.h +++ b/tests/api/test_ssl_crl_ocsp.h @@ -28,6 +28,7 @@ int test_wolfSSL_ocsp_url_api(void); int test_wolfSSL_get_ocsp_producedDate(void); int test_wolfSSL_tlsext_status_type(void); int test_wolfSSL_CTX_tlsext_status_cb(void); +int test_wolfSSL_CTX_set_ocsp_status_verify_cb(void); int test_wolfSSL_tlsext_status_ocsp_resp(void); int test_wolfSSL_OCSP_parse_url_api(void); @@ -36,6 +37,8 @@ int test_wolfSSL_OCSP_parse_url_api(void); TEST_DECL_GROUP("ssl_crl_ocsp", test_wolfSSL_get_ocsp_producedDate), \ TEST_DECL_GROUP("ssl_crl_ocsp", test_wolfSSL_tlsext_status_type), \ TEST_DECL_GROUP("ssl_crl_ocsp", test_wolfSSL_CTX_tlsext_status_cb), \ + TEST_DECL_GROUP("ssl_crl_ocsp", \ + test_wolfSSL_CTX_set_ocsp_status_verify_cb), \ TEST_DECL_GROUP("ssl_crl_ocsp", test_wolfSSL_tlsext_status_ocsp_resp), \ TEST_DECL_GROUP("ssl_crl_ocsp", test_wolfSSL_OCSP_parse_url_api) diff --git a/tests/unit-mcdc/test_internal_status_whitebox.c b/tests/unit-mcdc/test_internal_status_whitebox.c index ea8c1bd10e1..91738a5b1bf 100644 --- a/tests/unit-mcdc/test_internal_status_whitebox.c +++ b/tests/unit-mcdc/test_internal_status_whitebox.c @@ -64,9 +64,16 @@ static int wb_send_sink(WOLFSSL* ssl, char* buf, int sz, void* ctx) /* ------------------------------------------------- CsrDoStatusVerifyCb */ -#if !defined(NO_WOLFSSL_SERVER) && \ - (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ - defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) +#if (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ + defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) && \ + (!defined(WOLFSSL_NO_TLS12) || \ + (defined(HAVE_OCSP) && defined(WOLFSSL_TLS13) && \ + defined(HAVE_CERTIFICATE_STATUS_REQUEST))) && \ + (!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH)) + #define WB_HAVE_CSR_VERIFY_CB +#endif + +#ifdef WB_HAVE_CSR_VERIFY_CB static int g_verRet; /* what the mock callback returns */ @@ -207,9 +214,7 @@ int main(void) goto done; } -#if !defined(NO_WOLFSSL_SERVER) && \ - (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ - defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) +#ifdef WB_HAVE_CSR_VERIFY_CB wb_csr_status_verify(ssl, ctx); #endif wb_do_certificate_status(ssl, ctx); diff --git a/wolfssl/internal.h b/wolfssl/internal.h index d293decb603..dcf0ba4e0c3 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -4790,13 +4790,16 @@ struct WOLFSSL_CTX { #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) OcspRequest* certOcspRequest; - ocspVerifyStatusCb ocspStatusVerifyCb; - void* ocspStatusVerifyCbArg; #endif #if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) OcspRequest* chainOcspRequest[MAX_CHAIN_DEPTH]; #endif #endif + #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) + ocspVerifyStatusCb ocspStatusVerifyCb; + void* ocspStatusVerifyCbArg; + #endif #if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) SessionTicketEncCb ticketEncCb; /* enc/dec session ticket Cb */ void* ticketEncCtx; /* session encrypt context */ diff --git a/wolfssl/wolfio.h b/wolfssl/wolfio.h index 56b3f96879e..b359cace2bd 100644 --- a/wolfssl/wolfio.h +++ b/wolfssl/wolfio.h @@ -505,6 +505,10 @@ #define SEND_FUNCTION send #define RECV_FUNCTION recv #endif + #if defined(HAVE_HTTP_CLIENT) && !defined(HAVE_SOCKADDR) && \ + !defined(WOLFSSL_NO_SOCK) + #define HAVE_SOCKADDR + #endif #elif defined(WOLFSSL_LINUXKM) #define SEND_FUNCTION linuxkm_send #define RECV_FUNCTION linuxkm_recv @@ -578,6 +582,9 @@ #endif /* HAVE_SOCKADDR */ #if defined(WOLFSSL_ZEPHYR) + #ifndef HAVE_GETADDRINFO + #define HAVE_GETADDRINFO + #endif typedef struct zsock_addrinfo ADDRINFO; #define getaddrinfo zsock_getaddrinfo #define freeaddrinfo zsock_freeaddrinfo