ngx_event_openssl.c
来自「Nginx是一个高性能的HTTP和反向代理服务器」· C语言 代码 · 共 1,975 行 · 第 1/4 页
C
1,975 行
return NGX_AGAIN; } c->ssl->no_wait_shutdown = 1; c->ssl->no_send_shutdown = 1; c->write->error = 1; ngx_ssl_connection_error(c, sslerr, err, "SSL_write() failed"); return NGX_ERROR;}static voidngx_ssl_read_handler(ngx_event_t *rev){ ngx_connection_t *c; c = rev->data; c->write->handler(c->write);}voidngx_ssl_free_buffer(ngx_connection_t *c){ if (c->ssl->buf && c->ssl->buf->start) { if (ngx_pfree(c->pool, c->ssl->buf->start) == NGX_OK) { c->ssl->buf->start = NULL; } }}ngx_int_tngx_ssl_shutdown(ngx_connection_t *c){ int n, sslerr, mode; ngx_err_t err; if (c->timedout) { mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN; } else { mode = SSL_get_shutdown(c->ssl->connection); if (c->ssl->no_wait_shutdown) { mode |= SSL_RECEIVED_SHUTDOWN; } if (c->ssl->no_send_shutdown) { mode |= SSL_SENT_SHUTDOWN; } } SSL_set_shutdown(c->ssl->connection, mode); ngx_ssl_clear_error(c->log); n = SSL_shutdown(c->ssl->connection); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); sslerr = 0; /* SSL_shutdown() never returns -1, on error it returns 0 */ if (n != 1 && ERR_peek_error()) { sslerr = SSL_get_error(c->ssl->connection, n); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); } if (n == 1 || sslerr == 0 || sslerr == SSL_ERROR_ZERO_RETURN) { SSL_free(c->ssl->connection); c->ssl = NULL; return NGX_OK; } if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) { c->read->handler = ngx_ssl_shutdown_handler; c->write->handler = ngx_ssl_shutdown_handler; if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { return NGX_ERROR; } if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { return NGX_ERROR; } if (sslerr == SSL_ERROR_WANT_READ) { ngx_add_timer(c->read, 30000); } return NGX_AGAIN; } err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; ngx_ssl_connection_error(c, sslerr, err, "SSL_shutdown() failed"); SSL_free(c->ssl->connection); c->ssl = NULL; return NGX_ERROR;}static voidngx_ssl_shutdown_handler(ngx_event_t *ev){ ngx_connection_t *c; ngx_connection_handler_pt handler; c = ev->data; handler = c->ssl->handler; if (ev->timedout) { c->timedout = 1; } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "SSL shutdown handler"); if (ngx_ssl_shutdown(c) == NGX_AGAIN) { return; } handler(c);}static voidngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, char *text){ int n; ngx_uint_t level; level = NGX_LOG_CRIT; if (sslerr == SSL_ERROR_SYSCALL) { if (err == NGX_ECONNRESET || err == NGX_EPIPE || err == NGX_ENOTCONN#if !(NGX_CRIT_ETIMEDOUT) || err == NGX_ETIMEDOUT#endif || err == NGX_ECONNREFUSED || err == NGX_ENETDOWN || err == NGX_ENETUNREACH || err == NGX_EHOSTDOWN || err == NGX_EHOSTUNREACH) { switch (c->log_error) { case NGX_ERROR_IGNORE_ECONNRESET: case NGX_ERROR_INFO: level = NGX_LOG_INFO; break; case NGX_ERROR_ERR: level = NGX_LOG_ERR; break; default: break; } } } else if (sslerr == SSL_ERROR_SSL) { n = ERR_GET_REASON(ERR_peek_error()); /* handshake failures */ if (n == SSL_R_DIGEST_CHECK_FAILED || n == SSL_R_NO_SHARED_CIPHER || n == SSL_R_UNEXPECTED_MESSAGE || n == SSL_R_WRONG_VERSION_NUMBER || n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC || n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */ || n == SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE || n == SSL_R_SSLV3_ALERT_BAD_RECORD_MAC || n == SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE || n == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE || n == SSL_R_SSLV3_ALERT_BAD_CERTIFICATE || n == SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE || n == SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED || n == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED || n == SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN || n == SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER || n == SSL_R_TLSV1_ALERT_UNKNOWN_CA) { switch (c->log_error) { case NGX_ERROR_IGNORE_ECONNRESET: case NGX_ERROR_INFO: level = NGX_LOG_INFO; break; case NGX_ERROR_ERR: level = NGX_LOG_ERR; break; default: break; } } } ngx_ssl_error(level, c->log, err, text);}static voidngx_ssl_clear_error(ngx_log_t *log){ while (ERR_peek_error()) { ngx_ssl_error(NGX_LOG_ALERT, log, 0, "ignoring stale global SSL error"); } ERR_clear_error();}void ngx_cdeclngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...){ u_long n; va_list args; u_char *p, *last; u_char errstr[NGX_MAX_CONF_ERRSTR]; last = errstr + NGX_MAX_CONF_ERRSTR; va_start(args, fmt); p = ngx_vsnprintf(errstr, sizeof(errstr) - 1, fmt, args); va_end(args); p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p); for ( ;; ) { n = ERR_get_error(); if (n == 0) { break; } if (p >= last) { continue; } *p++ = ' '; ERR_error_string_n(n, (char *) p, last - p); while (p < last && *p) { p++; } } ngx_log_error(level, log, err, "%s)", errstr);}ngx_int_tngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout){ long cache_mode; if (builtin_session_cache == NGX_SSL_NO_SCACHE) { SSL_CTX_set_session_cache_mode(ssl->ctx, SSL_SESS_CACHE_OFF); return NGX_OK; } cache_mode = SSL_SESS_CACHE_SERVER; if (shm_zone && builtin_session_cache == NGX_SSL_NO_BUILTIN_SCACHE) { cache_mode |= SSL_SESS_CACHE_NO_INTERNAL; } SSL_CTX_set_session_cache_mode(ssl->ctx, cache_mode); SSL_CTX_set_session_id_context(ssl->ctx, sess_ctx->data, sess_ctx->len); if (builtin_session_cache != NGX_SSL_NO_BUILTIN_SCACHE) { if (builtin_session_cache != NGX_SSL_DFLT_BUILTIN_SCACHE) { SSL_CTX_sess_set_cache_size(ssl->ctx, builtin_session_cache); } } SSL_CTX_set_timeout(ssl->ctx, timeout); if (shm_zone) { shm_zone->init = ngx_ssl_session_cache_init; SSL_CTX_sess_set_new_cb(ssl->ctx, ngx_ssl_new_session); SSL_CTX_sess_set_get_cb(ssl->ctx, ngx_ssl_get_cached_session); SSL_CTX_sess_set_remove_cb(ssl->ctx, ngx_ssl_remove_session); if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_cache_index, shm_zone) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_set_ex_data() failed"); return NGX_ERROR; } } return NGX_OK;}static ngx_int_tngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data){ ngx_slab_pool_t *shpool; ngx_ssl_session_cache_t *cache; if (data) { shm_zone->data = data; return NGX_OK; } shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_session_cache_t)); if (cache == NULL) { return NGX_ERROR; } ngx_rbtree_init(&cache->session_rbtree, &cache->sentinel, ngx_ssl_session_rbtree_insert_value); ngx_queue_init(&cache->expire_queue); shm_zone->data = cache; return NGX_OK;}/* * The length of the session id is 16 bytes for SSLv2 sessions and * between 1 and 32 bytes for SSLv3/TLSv1, typically 32 bytes. * It seems that the typical length of the external ASN1 representation * of a session is 118 or 119 bytes for SSLv3/TSLv1. * * Thus on 32-bit platforms we allocate separately an rbtree node, * a session id, and an ASN1 representation, they take accordingly * 64, 32, and 128 bytes. * * On 64-bit platforms we allocate separately an rbtree node + session_id, * and an ASN1 representation, they take accordingly 128 and 128 bytes. * * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow, * so they are outside the code locked by shared pool mutex */static intngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess){ int len; u_char *p, *id, *cached_sess; uint32_t hash; SSL_CTX *ssl_ctx; ngx_shm_zone_t *shm_zone; ngx_connection_t *c; ngx_slab_pool_t *shpool; ngx_ssl_sess_id_t *sess_id; ngx_ssl_session_cache_t *cache; u_char buf[NGX_SSL_MAX_SESSION_SIZE]; len = i2d_SSL_SESSION(sess, NULL); /* do not cache too big session */ if (len > (int) NGX_SSL_MAX_SESSION_SIZE) { return 0; } p = buf; i2d_SSL_SESSION(sess, &p); c = ngx_ssl_get_connection(ssl_conn); ssl_ctx = SSL_get_SSL_CTX(ssl_conn); shm_zone = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_cache_index); cache = shm_zone->data; shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; ngx_shmtx_lock(&shpool->mutex); /* drop one or two expired sessions */ ngx_ssl_expire_sessions(cache, shpool, 1); cached_sess = ngx_slab_alloc_locked(shpool, len); if (cached_sess == NULL) { /* drop the oldest non-expired session and try once more */ ngx_ssl_expire_sessions(cache, shpool, 0); cached_sess = ngx_slab_alloc_locked(shpool, len); if (cached_sess == NULL) { sess_id = NULL; goto failed; } } sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t)); if (sess_id == NULL) { goto failed; }#if (NGX_PTR_SIZE == 8) id = sess_id->sess_id;#else id = ngx_slab_alloc_locked(shpool, sess->session_id_length); if (id == NULL) { goto failed; }#endif ngx_memcpy(cached_sess, buf, len); ngx_memcpy(id, sess->session_id, sess->session_id_length); hash = ngx_crc32_short(sess->session_id, sess->session_id_length); ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "http ssl new session: %08XD:%d:%d", hash, sess->session_id_length, len); sess_id->node.key = hash; sess_id->node.data = (u_char) sess->session_id_length; sess_id->id = id; sess_id->len = len; sess_id->session = cached_sess; sess_id->expire = ngx_time() + SSL_CTX_get_timeout(ssl_ctx); ngx_queue_insert_head(&cache->expire_queue, &sess_id->queue); ngx_rbtree_insert(&cache->session_rbtree, &sess_id->node); ngx_shmtx_unlock(&shpool->mutex); return 0;failed: if (cached_sess) { ngx_slab_free_locked(shpool, cached_sess); } if (sess_id) { ngx_slab_free_locked(shpool, sess_id); } ngx_shmtx_unlock(&shpool->mutex); ngx_log_error(NGX_LOG_ALERT, c->log, 0, "could not add new SSL session to the session cache"); return 0;}static ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, u_char *id, int len, int *copy){#if OPENSSL_VERSION_NUMBER >= 0x0090707fL const#endif u_char *p; uint32_t hash; ngx_int_t rc; ngx_shm_zone_t *shm_zone;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?