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 {