Skip to content

Commit

Permalink
Release 2.27.0
Browse files Browse the repository at this point in the history
- [API] Remove keylog callbacks.  See issue #188.
- Add a bit more ALPN logging.
  • Loading branch information
Dmitri Tikhonov committed Dec 31, 2020
1 parent 292abba commit 6511378
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 176 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
2020-12-31
- 2.27.0
- [API] Remove keylog callbacks. See issue #188.
- Add a bit more ALPN logging.

2020-12-23
- 2.26.2
- [BUGFIX] Do not drop incoming data when STOP_SENDING is received.
Expand Down
107 changes: 61 additions & 46 deletions bin/prog.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@
#include "prog.h"

static int prog_stopped;
static const char *s_keylog_dir;

static SSL_CTX * get_ssl_ctx (void *, const struct sockaddr *);
static void keylog_log_line (const SSL *, const char *);

static const struct lsquic_packout_mem_if pmi = {
.pmi_allocate = pba_allocate,
Expand Down Expand Up @@ -81,7 +83,7 @@ prog_init (struct prog *prog, unsigned flags,
= prog;
prog->prog_api.ea_pmi = &pmi;
prog->prog_api.ea_pmi_ctx = &prog->prog_pba;
prog->prog_api.ea_get_ssl_ctx = flags & LSENG_SERVER ? get_ssl_ctx : NULL;
prog->prog_api.ea_get_ssl_ctx = get_ssl_ctx;
#if LSQUIC_PREFERRED_ADDR
if (getenv("LSQUIC_PREFERRED_ADDR4") || getenv("LSQUIC_PREFERRED_ADDR6"))
prog->prog_flags |= PROG_SEARCH_ADDRS;
Expand Down Expand Up @@ -356,7 +358,7 @@ prog_set_opt (struct prog *prog, int opt, const char *arg)
return -1;
}
}
prog->prog_keylog_dir = optarg;
s_keylog_dir = optarg;
if (prog->prog_settings.es_ql_bits)
{
LSQ_NOTICE("QL loss bits turned off because of -G. If you want "
Expand Down Expand Up @@ -425,29 +427,41 @@ get_ssl_ctx (void *peer_ctx, const struct sockaddr *unused)


static int
prog_init_server (struct prog *prog)
prog_init_ssl_ctx (struct prog *prog)
{
struct service_port *sport;
unsigned char ticket_keys[48];

prog->prog_ssl_ctx = SSL_CTX_new(TLS_method());
if (prog->prog_ssl_ctx)
if (!prog->prog_ssl_ctx)
{
SSL_CTX_set_min_proto_version(prog->prog_ssl_ctx, TLS1_3_VERSION);
SSL_CTX_set_max_proto_version(prog->prog_ssl_ctx, TLS1_3_VERSION);
SSL_CTX_set_default_verify_paths(prog->prog_ssl_ctx);

/* This is obviously test code: the key is just an array of NUL bytes */
memset(ticket_keys, 0, sizeof(ticket_keys));
if (1 != SSL_CTX_set_tlsext_ticket_keys(prog->prog_ssl_ctx,
ticket_keys, sizeof(ticket_keys)))
{
LSQ_ERROR("SSL_CTX_set_tlsext_ticket_keys failed");
return -1;
}
LSQ_ERROR("cannot allocate SSL context");
return -1;
}
else
LSQ_WARN("cannot create SSL context");

SSL_CTX_set_min_proto_version(prog->prog_ssl_ctx, TLS1_3_VERSION);
SSL_CTX_set_max_proto_version(prog->prog_ssl_ctx, TLS1_3_VERSION);
SSL_CTX_set_default_verify_paths(prog->prog_ssl_ctx);

/* This is obviously test code: the key is just an array of NUL bytes */
memset(ticket_keys, 0, sizeof(ticket_keys));
if (1 != SSL_CTX_set_tlsext_ticket_keys(prog->prog_ssl_ctx,
ticket_keys, sizeof(ticket_keys)))
{
LSQ_ERROR("SSL_CTX_set_tlsext_ticket_keys failed");
return -1;
}

if (s_keylog_dir)
SSL_CTX_set_keylog_callback(prog->prog_ssl_ctx, keylog_log_line);

return 0;
}


static int
prog_init_server (struct prog *prog)
{
struct service_port *sport;

TAILQ_FOREACH(sport, prog->prog_sports, next_sport)
if (0 != sport_init_server(sport, prog->prog_engine, prog->prog_eb))
Expand Down Expand Up @@ -582,55 +596,46 @@ prog_stop (struct prog *prog)


static void *
keylog_open (void *ctx, lsquic_conn_t *conn)
keylog_open_file (const SSL *ssl)
{
const struct prog *const prog = ctx;
const lsquic_conn_t *conn;
const lsquic_cid_t *cid;
FILE *fh;
int sz;
char id_str[MAX_CID_LEN * 2 + 1];
char path[PATH_MAX];

conn = lsquic_ssl_to_conn(ssl);
cid = lsquic_conn_id(conn);
lsquic_hexstr(cid->idbuf, cid->len, id_str, sizeof(id_str));
sz = snprintf(path, sizeof(path), "%s/%s.keys", prog->prog_keylog_dir,
id_str);
sz = snprintf(path, sizeof(path), "%s/%s.keys", s_keylog_dir, id_str);
if ((size_t) sz >= sizeof(path))
{
LSQ_WARN("%s: file too long", __func__);
return NULL;
}
fh = fopen(path, "w");
fh = fopen(path, "ab");
if (!fh)
LSQ_WARN("could not open %s for writing: %s", path, strerror(errno));
LSQ_WARN("could not open %s for appending: %s", path, strerror(errno));
return fh;
}


static void
keylog_log_line (void *handle, const char *line)
keylog_log_line (const SSL *ssl, const char *line)
{
fputs(line, handle);
fputs("\n", handle);
fflush(handle);
}
FILE *file;


static void
keylog_close (void *handle)
{
fclose(handle);
file = keylog_open_file(ssl);
if (file)
{
fputs(line, file);
fputs("\n", file);
fclose(file);
}
}


static const struct lsquic_keylog_if keylog_if =
{
.kli_open = keylog_open,
.kli_log_line = keylog_log_line,
.kli_close = keylog_close,
};


static struct ssl_ctx_st *
no_cert (void *cert_lu_ctx, const struct sockaddr *sa_UNUSED, const char *sni)
{
Expand All @@ -644,10 +649,17 @@ prog_prep (struct prog *prog)
int s;
char err_buf[100];

if (prog->prog_keylog_dir)
if (s_keylog_dir && prog->prog_certs)
{
prog->prog_api.ea_keylog_if = &keylog_if;
prog->prog_api.ea_keylog_ctx = prog;
struct lsquic_hash_elem *el;
struct server_cert *cert;

for (el = lsquic_hash_first(prog->prog_certs); el;
el = lsquic_hash_next(prog->prog_certs))
{
cert = lsquic_hashelem_getdata(el);
SSL_CTX_set_keylog_callback(cert->ce_ssl_ctx, keylog_log_line);
}
}

if (0 != lsquic_engine_check_settings(prog->prog_api.ea_settings,
Expand Down Expand Up @@ -696,6 +708,9 @@ prog_prep (struct prog *prog)
prog->prog_timer = event_new(prog->prog_eb, -1, 0,
prog_timer_handler, prog);

if (0 != prog_init_ssl_ctx(prog))
return -1;

if (prog->prog_engine_flags & LSENG_SERVER)
s = prog_init_server(prog);
else
Expand Down
1 change: 0 additions & 1 deletion bin/prog.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ struct prog
struct lsquic_engine *prog_engine;
const char *prog_hostname;
int prog_ipver; /* 0, 4, or 6 */
const char *prog_keylog_dir;
enum {
PROG_FLAG_COOLDOWN = 1 << 0,
#if LSQUIC_PREFERRED_ADDR
Expand Down
20 changes: 4 additions & 16 deletions docs/apiref.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1981,6 +1981,10 @@ Miscellaneous Stream Functions
Other Functions
---------------

.. function:: lsquic_conn_t lsquic_ssl_to_conn (const SSL *)

Get connection associated with this SSL object.

.. function:: enum lsquic_version lsquic_str2ver (const char *str, size_t len)

Translate string QUIC version to LSQUIC QUIC version representation.
Expand Down Expand Up @@ -2103,22 +2107,6 @@ Miscellaneous Types

Number of elements in the peer context pointer and connection ID arrays.

.. type:: struct lsquic_keylog_if

SSL keylog interface.

.. member:: void * (*kli_open) (void *keylog_ctx, lsquic_conn_t *conn)

Return keylog handle or NULL if no key logging is desired.

.. member:: void (*kli_log_line) (void *handle, const char *line)

Log line. The first argument is the pointer returned by ``kli_open()``.

.. member:: void (*kli_close) (void *handle)

Close handle.

.. type:: enum lsquic_logger_timestamp_style

Enumerate timestamp styles supported by LSQUIC logger mechanism.
Expand Down
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
author = u'LiteSpeed Technologies'

# The short X.Y version
version = u'2.26'
version = u'2.27'
# The full version, including alpha/beta/rc tags
release = u'2.26.2'
release = u'2.27.0'


# -- General configuration ---------------------------------------------------
Expand Down
57 changes: 21 additions & 36 deletions docs/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1078,37 +1078,19 @@ Key logging and Wireshark
`Wireshark`_ supports IETF QUIC. The developers have been very good at keeping up with latest versions.
You will need version 3.3 of Wireshark to support Internet-Draft 29. Support for HTTP/3 is in progress.

LSQUIC supports exporting TLS secrets. For that, you need to specify a set of function pointers via
:member:`lsquic_engine_api.ea_keylog_if`.

::

/* Secrets are logged per connection. Interface to open file (handle),
* log lines, and close file.
*/
struct lsquic_keylog_if {
void * (*kli_open) (void *keylog_ctx, lsquic_conn_t *);
void (*kli_log_line) (void *handle, const char *line);
void (*kli_close) (void *handle);
};

struct lsquic_engine_api {
/* --- 8< --- snip --- 8< --- */
const struct lsquic_keylog_if *ea_keylog_if;
void *ea_keylog_ctx;
};

There are three functions: one to open a file, one to write a line into the file, and one to close the file. The lines are not interpreted.
In the engine API struct, there are two members to set: one is the pointer to the struct with the function pointers, and the other is the context passed to "kli_open" function.
To export TLS secrets, use BoringSSL's ``SSL_CTX_set_keylog_callback()``.
Use `lsquic_ssl_to_conn()` to get the connection associated
with the SSL object.

Key logging example
-------------------

::

static void *
keylog_open (void *ctx, lsquic_conn_t *conn)
keylog_open_file (const SSL *ssl)
{
const lsquic_conn_t *conn;
const lsquic_cid_t *cid;
FILE *fh;
int sz;
Expand All @@ -1117,6 +1099,7 @@ Key logging example
char path[PATH_MAX];
static const char b2c[16] = "0123456789ABCDEF";

conn = lsquic_ssl_to_conn(ssl);
cid = lsquic_conn_id(conn);
for (i = 0; i < cid->len; ++i)
{
Expand All @@ -1130,28 +1113,30 @@ Key logging example
LOG("WARN: %s: file too long", __func__);
return NULL;
}
fh = fopen(path, "wb");
fh = fopen(path, "ab");
if (!fh)
LOG("WARN: could not open %s for writing: %s", path, strerror(errno));
LOG("WARN: could not open %s for appending: %s", path, strerror(errno));
return fh;
}

static void
keylog_log_line (void *handle, const char *line)
keylog_log_line (const SSL *ssl, const char *line)
{
fputs(line, handle);
fputs("\n", handle);
fflush(handle);
file = keylog_open_file(ssl);
if (file)
{
fputs(line, file);
fputs("\n", file);
fclose(file);
}
}

static void
keylog_close (void *handle)
{
fclose(handle);
}
/* ... */

SSL_CTX_set_keylog_callback(ssl, keylog_log_line);

The function to open the file is passed the connection object. It can be used to generate a filename
based on the connection ID.
The most involved part of this is opening the necessary file, creating it if necessary.
The connection can be used to generate a filename based on the connection ID.
We see that the line logger simply writes the passed C string to the filehandle and appends a newline.

Wireshark screenshot
Expand Down
Loading

0 comments on commit 6511378

Please sign in to comment.