Line data Source code
1 : #include "fd_openssl.h" 2 : 3 : #if !FD_HAS_OPENSSL 4 : #error "fd_openssl.c requires FD_HAS_OPENSSL" 5 : #endif 6 : 7 : #include "../../util/log/fd_log.h" 8 : 9 : #include <openssl/ssl.h> 10 : #include <openssl/bio.h> 11 : #include <sys/socket.h> 12 : #include <unistd.h> 13 : #include <string.h> 14 : #include <errno.h> 15 : 16 : FD_FN_CONST char const * 17 0 : fd_openssl_ssl_strerror( int ssl_err ) { 18 0 : switch( ssl_err ) { 19 0 : case SSL_ERROR_NONE: return "SSL_ERROR_NONE"; 20 0 : case SSL_ERROR_SSL: return "SSL_ERROR_SSL"; 21 0 : case SSL_ERROR_WANT_READ: return "SSL_ERROR_WANT_READ"; 22 0 : case SSL_ERROR_WANT_WRITE: return "SSL_ERROR_WANT_WRITE"; 23 0 : case SSL_ERROR_WANT_X509_LOOKUP: return "SSL_ERROR_WANT_X509_LOOKUP"; 24 0 : case SSL_ERROR_SYSCALL: return "SSL_ERROR_SYSCALL"; 25 0 : case SSL_ERROR_ZERO_RETURN: return "SSL_ERROR_ZERO_RETURN"; 26 0 : case SSL_ERROR_WANT_CONNECT: return "SSL_ERROR_WANT_CONNECT"; 27 0 : case SSL_ERROR_WANT_ACCEPT: return "SSL_ERROR_WANT_ACCEPT"; 28 0 : case SSL_ERROR_WANT_ASYNC: return "SSL_ERROR_WANT_ASYNC"; 29 0 : case SSL_ERROR_WANT_ASYNC_JOB: return "SSL_ERROR_WANT_ASYNC_JOB"; 30 0 : case SSL_ERROR_WANT_CLIENT_HELLO_CB: return "SSL_ERROR_WANT_CLIENT_HELLO_CB"; 31 0 : case SSL_ERROR_WANT_RETRY_VERIFY: return "SSL_ERROR_WANT_RETRY_VERIFY"; 32 0 : default: return "unknown"; 33 0 : } 34 0 : } 35 : 36 : /* Custom BIO method that uses send(MSG_NOSIGNAL) instead of write() 37 : to prevent SIGPIPE on broken TCP connections. 38 : 39 : We implement all callbacks ourselves rather than copying them from 40 : BIO_s_socket() with the deprecated BIO_meth_get_* functions. */ 41 : 42 : struct fd_bio_sock_data { 43 : int fd; 44 : int close_flag; 45 : }; 46 : 47 : static int 48 0 : fd_bio_nosigpipe_create( BIO * bio ) { 49 0 : struct fd_bio_sock_data * data = OPENSSL_zalloc( sizeof(struct fd_bio_sock_data) ); 50 0 : if( FD_UNLIKELY( !data ) ) return 0; 51 0 : data->fd = -1; 52 0 : data->close_flag = BIO_NOCLOSE; 53 0 : BIO_set_data( bio, data ); 54 0 : return 1; 55 0 : } 56 : 57 : static int 58 0 : fd_bio_nosigpipe_destroy( BIO * bio ) { 59 0 : struct fd_bio_sock_data * data = BIO_get_data( bio ); 60 0 : if( FD_UNLIKELY( !data ) ) return 0; 61 0 : if( data->close_flag==BIO_CLOSE && data->fd>=0 ) { 62 0 : close( data->fd ); 63 0 : data->fd = -1; 64 0 : } 65 0 : OPENSSL_free( data ); 66 0 : BIO_set_data( bio, NULL ); 67 0 : BIO_set_init( bio, 0 ); 68 0 : return 1; 69 0 : } 70 : 71 : static int 72 : fd_bio_nosigpipe_write( BIO * bio, 73 : char const * buf, 74 0 : int len ) { 75 0 : struct fd_bio_sock_data * data = BIO_get_data( bio ); 76 0 : if( FD_UNLIKELY( !data || data->fd<0 ) ) return -1; 77 0 : if( FD_UNLIKELY( len<=0 ) ) return 0; 78 : 79 0 : BIO_clear_retry_flags( bio ); 80 0 : int ret = (int)sendto( data->fd, buf, (size_t)len, MSG_NOSIGNAL, NULL, 0 ); 81 0 : if( ret<=0 && BIO_sock_should_retry( ret ) ) { 82 0 : BIO_set_retry_write( bio ); 83 0 : } 84 0 : return ret; 85 0 : } 86 : 87 : static int 88 : fd_bio_nosigpipe_read( BIO * bio, 89 : char * buf, 90 0 : int len ) { 91 0 : struct fd_bio_sock_data * data = BIO_get_data( bio ); 92 0 : if( FD_UNLIKELY( !data || data->fd<0 ) ) return -1; 93 : 94 0 : BIO_clear_retry_flags( bio ); 95 0 : int ret = (int)read( data->fd, buf, (ulong)len ); 96 0 : if( ret<=0 && BIO_sock_should_retry( ret ) ) { 97 0 : BIO_set_retry_read( bio ); 98 0 : } 99 0 : return ret; 100 0 : } 101 : 102 : static long 103 : fd_bio_nosigpipe_ctrl( BIO * bio, 104 : int cmd, 105 : long num, 106 0 : void * ptr ) { 107 0 : struct fd_bio_sock_data * data = BIO_get_data( bio ); 108 0 : if( FD_UNLIKELY( !data ) ) return 0; 109 : 110 0 : switch( cmd ) { 111 0 : case BIO_C_SET_FD: 112 0 : if( data->close_flag==BIO_CLOSE && data->fd>=0 ) close( data->fd ); 113 0 : data->fd = *(int *)ptr; 114 0 : data->close_flag = (int)num; 115 0 : BIO_set_init( bio, (data->fd>=0) ); 116 0 : return 1; 117 0 : case BIO_C_GET_FD: 118 0 : if( data->fd<0 ) return -1; 119 0 : if( ptr ) *(int *)ptr = data->fd; 120 0 : return (long)data->fd; 121 0 : case BIO_CTRL_GET_CLOSE: 122 0 : return (long)data->close_flag; 123 0 : case BIO_CTRL_SET_CLOSE: 124 0 : data->close_flag = (int)num; 125 0 : return 1; 126 0 : case BIO_CTRL_FLUSH: 127 0 : return 1; 128 0 : default: 129 0 : return 0; 130 0 : } 131 0 : } 132 : 133 : static int 134 : fd_bio_nosigpipe_puts( BIO * bio, 135 0 : char const * str ) { 136 0 : return fd_bio_nosigpipe_write( bio, str, (int)strlen( str ) ); 137 0 : } 138 : 139 : static BIO_METHOD * fd_bio_nosigpipe_method_ptr; 140 : 141 : static void 142 0 : fd_bio_nosigpipe_method_init( void ) { 143 0 : BIO_METHOD * method = BIO_meth_new( BIO_TYPE_SOCKET, "socket(nosigpipe)" ); 144 0 : if( FD_UNLIKELY( !method ) ) FD_LOG_ERR(( "BIO_meth_new failed" )); 145 : 146 0 : if( FD_UNLIKELY( !BIO_meth_set_write ( method, fd_bio_nosigpipe_write ) ) ) FD_LOG_ERR(( "BIO_meth_set_write failed" )); 147 0 : if( FD_UNLIKELY( !BIO_meth_set_read ( method, fd_bio_nosigpipe_read ) ) ) FD_LOG_ERR(( "BIO_meth_set_read failed" )); 148 0 : if( FD_UNLIKELY( !BIO_meth_set_puts ( method, fd_bio_nosigpipe_puts ) ) ) FD_LOG_ERR(( "BIO_meth_set_puts failed" )); 149 0 : if( FD_UNLIKELY( !BIO_meth_set_ctrl ( method, fd_bio_nosigpipe_ctrl ) ) ) FD_LOG_ERR(( "BIO_meth_set_ctrl failed" )); 150 0 : if( FD_UNLIKELY( !BIO_meth_set_create ( method, fd_bio_nosigpipe_create ) ) ) FD_LOG_ERR(( "BIO_meth_set_create failed" )); 151 0 : if( FD_UNLIKELY( !BIO_meth_set_destroy( method, fd_bio_nosigpipe_destroy ) ) ) FD_LOG_ERR(( "BIO_meth_set_destroy failed" )); 152 : 153 0 : fd_bio_nosigpipe_method_ptr = method; 154 0 : } 155 : 156 : static BIO_METHOD * 157 0 : fd_bio_nosigpipe_method( void ) { 158 0 : FD_ONCE_BEGIN { 159 0 : fd_bio_nosigpipe_method_init(); 160 0 : } FD_ONCE_END; 161 0 : return fd_bio_nosigpipe_method_ptr; 162 0 : } 163 : 164 : BIO * 165 : fd_openssl_bio_new_socket( int fd, 166 0 : int close_flag ) { 167 0 : BIO_METHOD * method = fd_bio_nosigpipe_method(); 168 0 : if( FD_UNLIKELY( !method ) ) return NULL; 169 : 170 0 : BIO * bio = BIO_new( method ); 171 0 : if( FD_UNLIKELY( !bio ) ) return NULL; 172 0 : BIO_set_fd( bio, fd, close_flag ); 173 0 : return bio; 174 0 : }