Mercurial > hg > nginx
comparison src/event/ngx_event_openssl.c @ 7941:65946a191197
SSL: SSL_sendfile() support with kernel TLS.
Requires OpenSSL 3.0 compiled with "enable-ktls" option. Further, KTLS
needs to be enabled in kernel, and in OpenSSL, either via OpenSSL
configuration file or with "ssl_conf_command Options KTLS;" in nginx
configuration.
On FreeBSD, kernel TLS is available starting with FreeBSD 13.0, and
can be enabled with "sysctl kern.ipc.tls.enable=1" and "kldload ktls_ocf"
to load a software backend, see man ktls(4) for details.
On Linux, kernel TLS is available starting with kernel 4.13 (at least 5.2
is recommended), and needs kernel compiled with CONFIG_TLS=y (with
CONFIG_TLS=m, which is used at least on Ubuntu 21.04 by default,
the tls module needs to be loaded with "modprobe tls").
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 21 Oct 2021 18:44:07 +0300 |
parents | 46a02ed7c966 |
children | 3443c02ca1d1 61d0fa67b55e |
comparison
equal
deleted
inserted
replaced
7940:46a02ed7c966 | 7941:65946a191197 |
---|---|
45 static void ngx_ssl_write_handler(ngx_event_t *wev); | 45 static void ngx_ssl_write_handler(ngx_event_t *wev); |
46 #ifdef SSL_READ_EARLY_DATA_SUCCESS | 46 #ifdef SSL_READ_EARLY_DATA_SUCCESS |
47 static ssize_t ngx_ssl_write_early(ngx_connection_t *c, u_char *data, | 47 static ssize_t ngx_ssl_write_early(ngx_connection_t *c, u_char *data, |
48 size_t size); | 48 size_t size); |
49 #endif | 49 #endif |
50 static ssize_t ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, | |
51 size_t size); | |
50 static void ngx_ssl_read_handler(ngx_event_t *rev); | 52 static void ngx_ssl_read_handler(ngx_event_t *rev); |
51 static void ngx_ssl_shutdown_handler(ngx_event_t *ev); | 53 static void ngx_ssl_shutdown_handler(ngx_event_t *ev); |
52 static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, | 54 static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, |
53 ngx_err_t err, char *text); | 55 ngx_err_t err, char *text); |
54 static void ngx_ssl_clear_error(ngx_log_t *log); | 56 static void ngx_ssl_clear_error(ngx_log_t *log); |
1762 | 1764 |
1763 #endif | 1765 #endif |
1764 #endif | 1766 #endif |
1765 #endif | 1767 #endif |
1766 | 1768 |
1769 #ifdef BIO_get_ktls_send | |
1770 | |
1771 if (BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection)) == 1) { | |
1772 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1773 "BIO_get_ktls_send(): 1"); | |
1774 c->ssl->sendfile = 1; | |
1775 } | |
1776 | |
1777 #endif | |
1778 | |
1767 rc = ngx_ssl_ocsp_validate(c); | 1779 rc = ngx_ssl_ocsp_validate(c); |
1768 | 1780 |
1769 if (rc == NGX_ERROR) { | 1781 if (rc == NGX_ERROR) { |
1770 return NGX_ERROR; | 1782 return NGX_ERROR; |
1771 } | 1783 } |
1896 c->recv_chain = ngx_ssl_recv_chain; | 1908 c->recv_chain = ngx_ssl_recv_chain; |
1897 c->send_chain = ngx_ssl_send_chain; | 1909 c->send_chain = ngx_ssl_send_chain; |
1898 | 1910 |
1899 c->read->ready = 1; | 1911 c->read->ready = 1; |
1900 c->write->ready = 1; | 1912 c->write->ready = 1; |
1913 | |
1914 #ifdef BIO_get_ktls_send | |
1915 | |
1916 if (BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection)) == 1) { | |
1917 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1918 "BIO_get_ktls_send(): 1"); | |
1919 c->ssl->sendfile = 1; | |
1920 } | |
1921 | |
1922 #endif | |
1901 | 1923 |
1902 rc = ngx_ssl_ocsp_validate(c); | 1924 rc = ngx_ssl_ocsp_validate(c); |
1903 | 1925 |
1904 if (rc == NGX_ERROR) { | 1926 if (rc == NGX_ERROR) { |
1905 return NGX_ERROR; | 1927 return NGX_ERROR; |
2500 */ | 2522 */ |
2501 | 2523 |
2502 ngx_chain_t * | 2524 ngx_chain_t * |
2503 ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) | 2525 ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) |
2504 { | 2526 { |
2505 int n; | 2527 int n; |
2506 ngx_uint_t flush; | 2528 ngx_uint_t flush; |
2507 ssize_t send, size; | 2529 ssize_t send, size, file_size; |
2508 ngx_buf_t *buf; | 2530 ngx_buf_t *buf; |
2531 ngx_chain_t *cl; | |
2509 | 2532 |
2510 if (!c->ssl->buffer) { | 2533 if (!c->ssl->buffer) { |
2511 | 2534 |
2512 while (in) { | 2535 while (in) { |
2513 if (ngx_buf_special(in->buf)) { | 2536 if (ngx_buf_special(in->buf)) { |
2577 if (ngx_buf_special(in->buf)) { | 2600 if (ngx_buf_special(in->buf)) { |
2578 in = in->next; | 2601 in = in->next; |
2579 continue; | 2602 continue; |
2580 } | 2603 } |
2581 | 2604 |
2605 if (in->buf->in_file && c->ssl->sendfile) { | |
2606 flush = 1; | |
2607 break; | |
2608 } | |
2609 | |
2582 size = in->buf->last - in->buf->pos; | 2610 size = in->buf->last - in->buf->pos; |
2583 | 2611 |
2584 if (size > buf->end - buf->last) { | 2612 if (size > buf->end - buf->last) { |
2585 size = buf->end - buf->last; | 2613 size = buf->end - buf->last; |
2586 } | 2614 } |
2608 } | 2636 } |
2609 | 2637 |
2610 size = buf->last - buf->pos; | 2638 size = buf->last - buf->pos; |
2611 | 2639 |
2612 if (size == 0) { | 2640 if (size == 0) { |
2641 | |
2642 if (in && in->buf->in_file && send < limit) { | |
2643 | |
2644 /* coalesce the neighbouring file bufs */ | |
2645 | |
2646 cl = in; | |
2647 file_size = (size_t) ngx_chain_coalesce_file(&cl, limit - send); | |
2648 | |
2649 n = ngx_ssl_sendfile(c, in->buf, file_size); | |
2650 | |
2651 if (n == NGX_ERROR) { | |
2652 return NGX_CHAIN_ERROR; | |
2653 } | |
2654 | |
2655 if (n == NGX_AGAIN) { | |
2656 break; | |
2657 } | |
2658 | |
2659 in = ngx_chain_update_sent(in, n); | |
2660 | |
2661 send += n; | |
2662 flush = 0; | |
2663 | |
2664 continue; | |
2665 } | |
2666 | |
2613 buf->flush = 0; | 2667 buf->flush = 0; |
2614 c->buffered &= ~NGX_SSL_BUFFERED; | 2668 c->buffered &= ~NGX_SSL_BUFFERED; |
2669 | |
2615 return in; | 2670 return in; |
2616 } | 2671 } |
2617 | 2672 |
2618 n = ngx_ssl_write(c, buf->pos, size); | 2673 n = ngx_ssl_write(c, buf->pos, size); |
2619 | 2674 |
2634 flush = 0; | 2689 flush = 0; |
2635 | 2690 |
2636 buf->pos = buf->start; | 2691 buf->pos = buf->start; |
2637 buf->last = buf->start; | 2692 buf->last = buf->start; |
2638 | 2693 |
2639 if (in == NULL || send == limit) { | 2694 if (in == NULL || send >= limit) { |
2640 break; | 2695 break; |
2641 } | 2696 } |
2642 } | 2697 } |
2643 | 2698 |
2644 buf->flush = flush; | 2699 buf->flush = flush; |
2878 | 2933 |
2879 return NGX_ERROR; | 2934 return NGX_ERROR; |
2880 } | 2935 } |
2881 | 2936 |
2882 #endif | 2937 #endif |
2938 | |
2939 | |
2940 static ssize_t | |
2941 ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size) | |
2942 { | |
2943 #ifdef BIO_get_ktls_send | |
2944 | |
2945 int sslerr; | |
2946 ssize_t n; | |
2947 ngx_err_t err; | |
2948 | |
2949 ngx_ssl_clear_error(c->log); | |
2950 | |
2951 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
2952 "SSL to sendfile: @%O %uz", | |
2953 file->file_pos, size); | |
2954 | |
2955 ngx_set_errno(0); | |
2956 | |
2957 n = SSL_sendfile(c->ssl->connection, file->file->fd, file->file_pos, | |
2958 size, 0); | |
2959 | |
2960 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_sendfile: %d", n); | |
2961 | |
2962 if (n > 0) { | |
2963 | |
2964 if (c->ssl->saved_read_handler) { | |
2965 | |
2966 c->read->handler = c->ssl->saved_read_handler; | |
2967 c->ssl->saved_read_handler = NULL; | |
2968 c->read->ready = 1; | |
2969 | |
2970 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { | |
2971 return NGX_ERROR; | |
2972 } | |
2973 | |
2974 ngx_post_event(c->read, &ngx_posted_events); | |
2975 } | |
2976 | |
2977 c->sent += n; | |
2978 | |
2979 return n; | |
2980 } | |
2981 | |
2982 if (n == 0) { | |
2983 | |
2984 /* | |
2985 * if sendfile returns zero, then someone has truncated the file, | |
2986 * so the offset became beyond the end of the file | |
2987 */ | |
2988 | |
2989 ngx_log_error(NGX_LOG_ALERT, c->log, 0, | |
2990 "SSL_sendfile() reported that \"%s\" was truncated at %O", | |
2991 file->file->name.data, file->file_pos); | |
2992 | |
2993 return NGX_ERROR; | |
2994 } | |
2995 | |
2996 sslerr = SSL_get_error(c->ssl->connection, n); | |
2997 | |
2998 if (sslerr == SSL_ERROR_ZERO_RETURN) { | |
2999 | |
3000 /* | |
3001 * OpenSSL fails to return SSL_ERROR_SYSCALL if an error | |
3002 * happens during writing after close_notify alert from the | |
3003 * peer, and returns SSL_ERROR_ZERO_RETURN instead | |
3004 */ | |
3005 | |
3006 sslerr = SSL_ERROR_SYSCALL; | |
3007 } | |
3008 | |
3009 if (sslerr == SSL_ERROR_SSL | |
3010 && ERR_GET_REASON(ERR_peek_error()) == SSL_R_UNINITIALIZED | |
3011 && ngx_errno != 0) | |
3012 { | |
3013 /* | |
3014 * OpenSSL fails to return SSL_ERROR_SYSCALL if an error | |
3015 * happens in sendfile(), and returns SSL_ERROR_SSL with | |
3016 * SSL_R_UNINITIALIZED reason instead | |
3017 */ | |
3018 | |
3019 sslerr = SSL_ERROR_SYSCALL; | |
3020 } | |
3021 | |
3022 err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; | |
3023 | |
3024 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); | |
3025 | |
3026 if (sslerr == SSL_ERROR_WANT_WRITE) { | |
3027 | |
3028 if (c->ssl->saved_read_handler) { | |
3029 | |
3030 c->read->handler = c->ssl->saved_read_handler; | |
3031 c->ssl->saved_read_handler = NULL; | |
3032 c->read->ready = 1; | |
3033 | |
3034 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { | |
3035 return NGX_ERROR; | |
3036 } | |
3037 | |
3038 ngx_post_event(c->read, &ngx_posted_events); | |
3039 } | |
3040 | |
3041 c->write->ready = 0; | |
3042 return NGX_AGAIN; | |
3043 } | |
3044 | |
3045 if (sslerr == SSL_ERROR_WANT_READ) { | |
3046 | |
3047 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
3048 "SSL_sendfile: want read"); | |
3049 | |
3050 c->read->ready = 0; | |
3051 | |
3052 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { | |
3053 return NGX_ERROR; | |
3054 } | |
3055 | |
3056 /* | |
3057 * we do not set the timer because there is already | |
3058 * the write event timer | |
3059 */ | |
3060 | |
3061 if (c->ssl->saved_read_handler == NULL) { | |
3062 c->ssl->saved_read_handler = c->read->handler; | |
3063 c->read->handler = ngx_ssl_read_handler; | |
3064 } | |
3065 | |
3066 return NGX_AGAIN; | |
3067 } | |
3068 | |
3069 c->ssl->no_wait_shutdown = 1; | |
3070 c->ssl->no_send_shutdown = 1; | |
3071 c->write->error = 1; | |
3072 | |
3073 ngx_ssl_connection_error(c, sslerr, err, "SSL_sendfile() failed"); | |
3074 | |
3075 #else | |
3076 ngx_log_error(NGX_LOG_ALERT, c->log, 0, | |
3077 "SSL_sendfile() not available"); | |
3078 #endif | |
3079 | |
3080 return NGX_ERROR; | |
3081 } | |
2883 | 3082 |
2884 | 3083 |
2885 static void | 3084 static void |
2886 ngx_ssl_read_handler(ngx_event_t *rev) | 3085 ngx_ssl_read_handler(ngx_event_t *rev) |
2887 { | 3086 { |