Skip to content

Commit ba70bc2

Browse files
tls: Added tls_session_logger
A class that wraps around a typical logger that appends useful information about the connection when logging. Added use to the OpenSSL implementation. Signed-off-by: Michael Boquard <[email protected]>
1 parent 7c4344e commit ba70bc2

File tree

4 files changed

+144
-2
lines changed

4 files changed

+144
-2
lines changed

src/net/ossl.cc

+77-2
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,10 @@ class session : public enable_shared_from_this<session>, public session_impl {
747747

748748
session(session_type t, shared_ptr<tls::certificate_credentials> creds,
749749
std::unique_ptr<net::connected_socket_impl> sock, tls_options options = {})
750-
: _sock(std::move(sock))
750+
: _logger(this)
751+
, _sock(std::move(sock))
752+
, _local_address(fmt::format("{}", _sock->local_address()))
753+
, _remote_address(fmt::format("{}", _sock->remote_address()))
751754
, _creds(creds->_impl)
752755
, _in(_sock->source())
753756
, _out(_sock->sink())
@@ -815,11 +818,17 @@ class session : public enable_shared_from_this<session>, public session_impl {
815818
assert(_output_pending.available());
816819
}
817820

821+
const char * get_type_string() const {
822+
return _type == session_type::CLIENT ? "Client": "Server";
823+
}
824+
818825
// This function waits for the _output_pending future to resolve
819826
// If an error occurs, it is saved off into _error and returned
820827
future<> wait_for_output() {
828+
_logger.trace("wait_for_output");
821829
return std::exchange(_output_pending, make_ready_future())
822830
.handle_exception([this](auto ep) {
831+
_logger.debug("wait_for_output error: {}", ep);
823832
_error = ep;
824833
return make_exception_future(ep);
825834
});
@@ -891,7 +900,9 @@ class session : public enable_shared_from_this<session>, public session_impl {
891900
// will attempt to send the provided packet. If a renegotiation is needed
892901
// any unprocessed part of the packet is returned.
893902
future<net::packet> do_put(net::packet p) {
903+
_logger.trace("do_put");
894904
if (!connected()) {
905+
_logger.debug("do_put: not connected");
895906
return make_ready_future<net::packet>(std::move(p));
896907
}
897908
assert(_output_pending.available());
@@ -910,8 +921,10 @@ class session : public enable_shared_from_this<session>, public session_impl {
910921
size_t bytes_written = 0;
911922
auto write_rc = SSL_write_ex(
912923
_ssl.get(), frag_view.data(), frag_view.size(), &bytes_written);
924+
_logger.trace("do_put: SSL_write_ex: {}", write_rc);
913925
if (write_rc != 1) {
914926
const auto ssl_err = SSL_get_error(_ssl.get(), write_rc);
927+
_logger.trace("do_put: SSL_get_error: {}", ssl_err);
915928
if (ssl_err == SSL_ERROR_WANT_WRITE) {
916929
return wait_for_output().then([] {
917930
return stop_iteration::no;
@@ -922,6 +935,7 @@ class session : public enable_shared_from_this<session>, public session_impl {
922935
}
923936
return handle_do_put_ssl_err(ssl_err);
924937
} else {
938+
_logger.trace("do_put: bytes_written: {}", bytes_written);
925939
frag_view.remove_prefix(bytes_written);
926940
p.trim_front(bytes_written);
927941
return wait_for_output().then([] {
@@ -930,7 +944,8 @@ class session : public enable_shared_from_this<session>, public session_impl {
930944
}
931945
});
932946
}
933-
).then([&p] {
947+
).then([this, &p] {
948+
_logger.trace("do_put: returning packet of size: {}", p.len());
934949
return std::move(p);
935950
});
936951
}
@@ -940,6 +955,7 @@ class session : public enable_shared_from_this<session>, public session_impl {
940955
// Used to push unencrypted data through OpenSSL, which will
941956
// encrypt it and then place it into the output bio.
942957
future<> put(net::packet p) override {
958+
_logger.trace("put");
943959
constexpr size_t openssl_max_record_size = 16 * 1024;
944960
if (_error) {
945961
return make_exception_future(_error);
@@ -949,6 +965,7 @@ class session : public enable_shared_from_this<session>, public session_impl {
949965
std::system_error(EPIPE, std::system_category()));
950966
}
951967
if (!connected()) {
968+
_logger.trace("put: not connected, performing handshake");
952969
return handshake().then(
953970
[this, p = std::move(p)]() mutable { return put(std::move(p)); });
954971
}
@@ -966,8 +983,10 @@ class session : public enable_shared_from_this<session>, public session_impl {
966983
return do_put(std::move(p));
967984
}).then([this](net::packet p) {
968985
if (eof() || p.len() == 0) {
986+
_logger.trace("put: eof: {}, p.len(): {}", eof(), p.len());
969987
return make_ready_future();
970988
} else {
989+
_logger.trace("put: not completed packet sending, re-doing handshake");
971990
return handshake().then([this, p = std::move(p)]() mutable {
972991
return put(std::move(p));
973992
});
@@ -979,7 +998,9 @@ class session : public enable_shared_from_this<session>, public session_impl {
979998
// This function will walk through the handshake with a remote peer
980999
// If EOF is encountered, ENOTCONN is thrown
9811000
future<> do_handshake() {
1001+
_logger.trace("do_handshake");
9821002
if (eof()) {
1003+
_logger.trace("do_handshake: eof encountered");
9831004
// if we have experienced and eof, set the error and return
9841005
// GnuTLS will probably return GNUTLS_E_PREMATURE_TERMINATION
9851006
// from gnutls_handshake in this situation.
@@ -989,15 +1010,18 @@ class session : public enable_shared_from_this<session>, public session_impl {
9891010
"EOF encountered during handshake"));
9901011
return make_exception_future(_error);
9911012
} else if (connected()) {
1013+
_logger.trace("do_handshake: already connected");
9921014
return make_ready_future<>();
9931015
}
9941016
return do_until(
9951017
[this] { return connected() || eof(); },
9961018
[this] {
9971019
try {
9981020
auto n = SSL_do_handshake(_ssl.get());
1021+
_logger.trace("do_handshake: SSL_do_handshake: {}", n);
9991022
if (n <= 0) {
10001023
auto ssl_error = SSL_get_error(_ssl.get(), n);
1024+
_logger.trace("do_handshake: SSL_get_error: {}", ssl_error);
10011025
switch(ssl_error) {
10021026
case SSL_ERROR_NONE:
10031027
// probably shouldn't have gotten here
@@ -1020,6 +1044,7 @@ class session : public enable_shared_from_this<session>, public session_impl {
10201044
case SSL_ERROR_SSL:
10211045
{
10221046
auto ec = ERR_GET_REASON(ERR_peek_error());
1047+
_logger.debug("do_handshake: ERR_GET_REASON: {}", ec);
10231048
switch (ec) {
10241049
case SSL_R_UNEXPECTED_EOF_WHILE_READING:
10251050
// well in this situation, the remote end closed
@@ -1062,17 +1087,21 @@ class session : public enable_shared_from_this<session>, public session_impl {
10621087
// This function will attempt to pull data off of the _in stream
10631088
// if there isn't already data needing to be processed first.
10641089
future<> wait_for_input() {
1090+
_logger.trace("wait_for_input");
10651091
// If we already have data, then it needs to be processed
10661092
if (!_input.empty()) {
1093+
_logger.trace("wait_for_input: input not empty");
10671094
return make_ready_future();
10681095
}
10691096
return _in.get()
10701097
.then([this](buf_type buf) {
10711098
// Set EOF if it's empty
1099+
_logger.debug("wait_for_input: buffer {}empty", buf.empty() ? "is ": "");
10721100
_eof |= buf.empty();
10731101
_input = std::move(buf);
10741102
})
10751103
.handle_exception([this](auto ep) {
1104+
_logger.debug("wait_for_input: exception: {}", ep);
10761105
_error = ep;
10771106
return make_exception_future(ep);
10781107
});
@@ -1083,12 +1112,14 @@ class session : public enable_shared_from_this<session>, public session_impl {
10831112
// SSL session using SSL_read. If ther eis no data, then
10841113
// we will call perform_pull and wait for data to arrive.
10851114
future<buf_type> do_get() {
1115+
_logger.trace("do_get");
10861116
// Data is available to be pulled of the SSL session if there is pending
10871117
// data on the SSL session or there is data in the in_bio() which SSL reads
10881118
// from
10891119
auto data_to_pull = (BIO_ctrl_pending(in_bio()) + SSL_pending(_ssl.get())) > 0;
10901120
auto f = make_ready_future<>();
10911121
if (!data_to_pull) {
1122+
_logger.trace("do_get: no data to pull, waiting for input");
10921123
// If nothing is in the SSL buffers then we may have to wait for
10931124
// data to come in
10941125
f = wait_for_input();
@@ -1098,12 +1129,16 @@ class session : public enable_shared_from_this<session>, public session_impl {
10981129
return make_ready_future<buf_type>();
10991130
}
11001131
auto avail = BIO_ctrl_pending(in_bio()) + SSL_pending(_ssl.get());
1132+
_logger.trace("do_get: available: {}", avail);
11011133
buf_type buf(avail);
11021134
size_t bytes_read = 0;
11031135
auto read_result = SSL_read_ex(
11041136
_ssl.get(), buf.get_write(), avail, &bytes_read);
1137+
_logger.trace("do_get: SSL_read_ex: {}", read_result);
1138+
_logger.trace("do_get: SSL_read_ex bytes_ready: {}", bytes_read);
11051139
if (read_result != 1) {
11061140
const auto ssl_err = SSL_get_error(_ssl.get(), read_result);
1141+
_logger.trace("do_get: SSL_get_error: {}", ssl_err);
11071142
switch (ssl_err) {
11081143
case SSL_ERROR_ZERO_RETURN:
11091144
// Remote end has closed
@@ -1164,37 +1199,45 @@ class session : public enable_shared_from_this<session>, public session_impl {
11641199

11651200
// Called by user applications to pull data off of the TLS session
11661201
future<buf_type> get() override {
1202+
_logger.trace("get");
11671203
if (_error) {
11681204
return make_exception_future<buf_type>(_error);
11691205
}
11701206
if (_shutdown || eof()) {
11711207
return make_ready_future<buf_type>(buf_type());
11721208
}
11731209
if (!connected()) {
1210+
_logger.trace("get: not connected, performing handshake");
11741211
return handshake().then(std::bind(&session::get, this));
11751212
}
11761213
return with_semaphore(_in_sem, 1, std::bind(&session::do_get, this))
11771214
.then([this](buf_type buf) {
11781215
if (buf.empty() && !eof()) {
1216+
_logger.trace("get: buffer empty and not eof, performing handshake");
11791217
return handshake().then(std::bind(&session::get, this));
11801218
}
1219+
_logger.trace("get: returning buffer of size {}", buf.size());
11811220
return make_ready_future<buf_type>(std::move(buf));
11821221
});
11831222
}
11841223

11851224
// Performs shutdown
11861225
future<> do_shutdown() {
1226+
_logger.trace("do_shutdown");
11871227
if (_error || !connected()) {
1228+
_logger.trace("do_shutdown: error exists or not connected");
11881229
return make_ready_future();
11891230
}
11901231

11911232
auto res = SSL_shutdown(_ssl.get());
1233+
_logger.trace("do_shutdown: SSL_shutdown: {}", res);
11921234
if (res == 1) {
11931235
return wait_for_output();
11941236
} else if (res == 0) {
11951237
return yield().then([this] { return do_shutdown(); });
11961238
} else {
11971239
auto ssl_err = SSL_get_error(_ssl.get(), res);
1240+
_logger.trace("do_shutdown: SSL_get_error: {}", ssl_err);
11981241
switch (ssl_err) {
11991242
case SSL_ERROR_NONE:
12001243
// this is weird, yield and try again
@@ -1242,12 +1285,15 @@ class session : public enable_shared_from_this<session>, public session_impl {
12421285
}
12431286

12441287
void verify() {
1288+
_logger.trace("verify");
12451289
if (!_creds->_enable_certificate_verification) {
1290+
_logger.debug("verify: certificate verification disabled, skipping");
12461291
return;
12471292
}
12481293
// A success return code (0) does not signify if a cert was presented or not, that
12491294
// must be explicitly queried via SSL_get_peer_certificate
12501295
auto res = SSL_get_verify_result(_ssl.get());
1296+
_logger.trace("verify: SSL_get_verify_result: {}", res);
12511297
if (res != X509_V_OK) {
12521298
auto stat_str(X509_verify_cert_error_string(res));
12531299
auto dn = extract_dn_information();
@@ -1264,6 +1310,7 @@ class session : public enable_shared_from_this<session>, public session_impl {
12641310
}
12651311
throw verification_error(stat_str);
12661312
} else if (SSL_get0_peer_certificate(_ssl.get()) == nullptr) {
1313+
_logger.trace("verify: No peer certificate");
12671314
// If a peer certificate was not presented,
12681315
// SSL_get_verify_result will return X509_V_OK:
12691316
// https://www.openssl.org/docs/man3.0/man3/SSL_get_verify_result.html
@@ -1294,6 +1341,7 @@ class session : public enable_shared_from_this<session>, public session_impl {
12941341
// This function waits for eof() to occur on the input stream
12951342
// Unless wait_for_eof_on_shutdown is false
12961343
future<> wait_for_eof() {
1344+
_logger.trace("wait_for_eof");
12971345
if (!_options.wait_for_eof_on_shutdown) {
12981346
// Seastar option to allow users to just bypass EOF waiting
12991347
return make_ready_future();
@@ -1305,12 +1353,15 @@ class session : public enable_shared_from_this<session>, public session_impl {
13051353
return do_until(
13061354
[this] { return eof(); },
13071355
[this] { return do_get().discard_result(); });
1356+
}).finally([this] {
1357+
_logger.trace("wait_for_eof: complete");
13081358
});
13091359
}
13101360

13111361
// This function is called to kick off the handshake. It will obtain
13121362
// locks on the _in_sem and _out_sem semaphores and start the handshake.
13131363
future<> handshake() {
1364+
_logger.trace("handshake");
13141365
if (_creds->need_load_system_trust()) {
13151366
if (!SSL_CTX_set_default_verify_paths(_ctx.get())) {
13161367
throw make_ossl_error(
@@ -1332,6 +1383,7 @@ class session : public enable_shared_from_this<session>, public session_impl {
13321383
}
13331384

13341385
future<> shutdown() {
1386+
_logger.trace("shutdown");
13351387
// first, make sure any pending write is done.
13361388
// bye handshake is a flush operation, but this
13371389
// allows us to not pay extra attention to output state
@@ -1351,8 +1403,10 @@ class session : public enable_shared_from_this<session>, public session_impl {
13511403
}
13521404

13531405
void close() noexcept override {
1406+
_logger.trace("close");
13541407
// only do once.
13551408
if (!std::exchange(_shutdown, true)) {
1409+
_logger.trace("close: performing shutdown");
13561410
// running in background. try to bye-handshake us nicely, but after 10s we forcefully close.
13571411
engine().run_in_background(with_timeout(
13581412
timer<>::clock::now() + std::chrono::seconds(10), shutdown())
@@ -1465,6 +1519,14 @@ class session : public enable_shared_from_this<session>, public session_impl {
14651519
});
14661520
}
14671521

1522+
const sstring& local_address() const noexcept {
1523+
return _local_address;
1524+
}
1525+
1526+
const sstring& remote_address() const noexcept {
1527+
return _remote_address;
1528+
}
1529+
14681530
private:
14691531
std::vector<subject_alt_name> do_get_alt_name_information(const x509_ptr &peer_cert,
14701532
const std::unordered_set<subject_alt_name_type> &types) const {
@@ -1711,7 +1773,10 @@ class session : public enable_shared_from_this<session>, public session_impl {
17111773
BIO* out_bio() { return SSL_get_wbio(_ssl.get()); }
17121774

17131775
private:
1776+
tls_session_logger<session> _logger;
17141777
std::unique_ptr<net::connected_socket_impl> _sock;
1778+
sstring _local_address;
1779+
sstring _remote_address;
17151780
shared_ptr<tls::certificate_credentials::impl> _creds;
17161781
data_source _in;
17171782
data_sink _out;
@@ -1855,9 +1920,11 @@ int bio_create(BIO*) {
18551920
/// and set the retry write flag.
18561921
int bio_write_ex(BIO* b, const char * data, size_t dlen, size_t * written) {
18571922
auto session = unwrap_bio_ptr(b);
1923+
session->_logger.trace("bio_write_ex: dlen {}", dlen);
18581924
BIO_clear_retry_flags(b);
18591925

18601926
if (!session->_output_pending.available()) {
1927+
session->_logger.trace("bio_write_ex: nothing pending in output");
18611928
BIO_set_retry_write(b);
18621929
return 0;
18631930
}
@@ -1870,9 +1937,11 @@ int bio_write_ex(BIO* b, const char * data, size_t dlen, size_t * written) {
18701937
msg.append(std::string_view(data, dlen));
18711938
n = msg.size();
18721939
session->_output_pending = session->_out.put(std::move(msg).release());
1940+
session->_logger.trace("bio_write_ex: Appended {} bytes to output pending", n);
18731941
}
18741942

18751943
if (session->_output_pending.failed()) {
1944+
session->_logger.debug("bio_write_ex: output pending has error");
18761945
std::rethrow_exception(session->_output_pending.get_exception());
18771946
}
18781947

@@ -1882,9 +1951,11 @@ int bio_write_ex(BIO* b, const char * data, size_t dlen, size_t * written) {
18821951

18831952
return 1;
18841953
} catch(const std::system_error & e) {
1954+
session->_logger.debug("bio_write_ex: system error occurred: {}", e.what());
18851955
ERR_raise_data(ERR_LIB_SYS, e.code().value(), e.what());
18861956
session->_output_pending = make_exception_future<>(std::current_exception());
18871957
} catch(...) {
1958+
session->_logger.debug("bio_write_ex: unknown error occurred");
18881959
ERR_raise(ERR_LIB_SYS, EIO);
18891960
session->_output_pending = make_exception_future<>(std::current_exception());
18901961
}
@@ -1900,13 +1971,16 @@ int bio_write_ex(BIO* b, const char * data, size_t dlen, size_t * written) {
19001971
/// the _input buffer and return it to the caller.
19011972
int bio_read_ex(BIO* b, char * data, size_t dlen, size_t *readbytes) {
19021973
auto session = unwrap_bio_ptr(b);
1974+
session->_logger.trace("bio_read_ex: dlen: {}", dlen);
19031975
BIO_clear_retry_flags(b);
19041976
if (session->eof()) {
1977+
session->_logger.trace("bio_read_ex: eof");
19051978
BIO_set_flags(b, BIO_FLAGS_IN_EOF);
19061979
return 0;
19071980
}
19081981

19091982
if (session->_input.empty()) {
1983+
session->_logger.trace("bio_read_ex: input empty");
19101984
BIO_set_retry_read(b);
19111985
return 0;
19121986
}
@@ -1918,6 +1992,7 @@ int bio_read_ex(BIO* b, char * data, size_t dlen, size_t *readbytes) {
19181992
*readbytes = n;
19191993
}
19201994

1995+
session->_logger.trace("bio_read_ex: read {} bytes from input", n);
19211996
return 1;
19221997
}
19231998

src/net/tls-impl.cc

+2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ module seastar;
5454

5555
namespace seastar {
5656

57+
logger tls::tls_log("seastar-tls");
58+
5759
// Helper
5860
struct file_info {
5961
sstring filename;

0 commit comments

Comments
 (0)