Skip to content

Commit

Permalink
LIT-134 Add callback functions for pmtud
Browse files Browse the repository at this point in the history
  • Loading branch information
expressvpn-tom-l committed Oct 10, 2023
1 parent 76a3358 commit d9132fe
Show file tree
Hide file tree
Showing 11 changed files with 218 additions and 37 deletions.
69 changes: 68 additions & 1 deletion include/he.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,14 +270,50 @@ typedef enum he_connection_protocol {
HE_CONNECTION_PROTOCOL_DTLS_1_3 = 3
} he_connection_protocol_t;

/**
* @brief Lightway Path MTU Discovery states.
* @see RFC 8899 and RFC 4821
*/
typedef enum he_pmtud_state {
// The DISABLED state is the initial state before probing has started.
// It is also entered from any other state, when the PL indicates loss of
// connectivity. This state is left once the PL indicates connectivity to the
// remote PL. When transitioning to the BASE state, a probe packet of size
// BASE_PLPMTU can be sent immediately
HE_PMTUD_STATE_DISABLED = 0,

// The BASE state is used to confirm that the BASE_PLPMTU size is supported by
// the network path and is designed to allow an application to continue working
// when there are transient reductions in the actual PMTU. It also seeks to avoid
// long periods when a sender searching for a larger PLPMTU is unaware that
// packets are not being delivered due to a packet or ICMP black hole.
HE_PMTUD_STATE_BASE = 1,

// The SEARCHING state is the main probing state. This state is entered when
// probing for the BASE_PLPMTU completes.
HE_PMTUD_STATE_SEARCHING = 2,

// The SEARCH_COMPLETE state indicates that a search has completed. This is the
// normal maintenance state, where the PL is not probing to update the PLPMTU.
// DPLPMTUD remains in this state until either the PMTU_RAISE_TIMER expires or a
// black hole is detected.
HE_PMTUD_STATE_SEARCH_COMPLETE = 3,

// The ERROR state represents the case where either the network path is not known
// to support a PLPMTU of at least the BASE_PLPMTU size or when there is
// contradictory information about the network path that would otherwise result
// in excessive variation in the MPS signaled to the higher layer. The state
// implements a method to mitigate oscillation in the state-event engine.
HE_PMTUD_STATE_ERROR = 4,
} he_pmtud_state_t;

typedef struct he_ssl_ctx he_ssl_ctx_t;
typedef struct he_conn he_conn_t;
typedef struct he_plugin_chain he_plugin_chain_t;
typedef struct he_network_config_ipv4 he_network_config_ipv4_t;

/**
* @brief Data structure to hold all the state needed as a Helium client
*
*/
typedef struct he_client {
he_ssl_ctx_t *ssl_ctx;
Expand Down Expand Up @@ -468,6 +504,37 @@ typedef he_return_code_t (*he_populate_network_config_ipv4_cb_t)(he_conn_t *conn
he_network_config_ipv4_t *config,
void *context);

/**
* @brief The prototype for the Path MTU Discovery (PMTUD) time callback function
* @param conn A pointer to the connection that triggered this callback
* @param timeout The number of milliseconds to wait before calling the he_conn_pmtud_timeout
* function. If the timeout value is 0, the host application should cancel the timer.
* @param context A pointer to the user defined context
* @see he_conn_set_context Sets the value of the context pointer
*
* Lightway Path MTU Discovery needs to be able to resend probe messages if they are not received in
* time. As Lightway Core does not have its own threads or timers, it is up to the host application
* to tell Lightway Core when a certain amount of time has passed.
*
* The host application must register this callback to enable Path MTU discovery.
*
* @note Any pending timers should be reset with the value provided in the callback and there should
* only ever be one timer per connection context.
*/
typedef he_return_code_t (*he_pmtud_time_cb_t)(he_conn_t *conn, int timeout, void *context);

/**
* @brief The prototype for Lightway PMTUD state callback function
* @param conn A pointer to the connection that triggered this callback
* @param state The state that Lightway PMTUD has just entered
* @param context A pointer to the user defined context
* @see he_conn_set_context Sets the value of the context pointer
*
* Whenever Lightway PMTUD changes state, this function will be called.
*/
typedef he_return_code_t (*he_pmtud_state_change_cb_t)(he_conn_t *conn, he_pmtud_state_t state,
void *context);

typedef struct he_network_config_ipv4 {
char local_ip[HE_MAX_IPV4_STRING_LENGTH];
char peer_ip[HE_MAX_IPV4_STRING_LENGTH];
Expand Down
84 changes: 83 additions & 1 deletion public/he.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,14 +270,50 @@ typedef enum he_connection_protocol {
HE_CONNECTION_PROTOCOL_DTLS_1_3 = 3
} he_connection_protocol_t;

/**
* @brief Lightway Path MTU Discovery states.
* @see RFC 8899 and RFC 4821
*/
typedef enum he_pmtud_state {
// The DISABLED state is the initial state before probing has started.
// It is also entered from any other state, when the PL indicates loss of
// connectivity. This state is left once the PL indicates connectivity to the
// remote PL. When transitioning to the BASE state, a probe packet of size
// BASE_PLPMTU can be sent immediately
HE_PMTUD_STATE_DISABLED = 0,

// The BASE state is used to confirm that the BASE_PLPMTU size is supported by
// the network path and is designed to allow an application to continue working
// when there are transient reductions in the actual PMTU. It also seeks to avoid
// long periods when a sender searching for a larger PLPMTU is unaware that
// packets are not being delivered due to a packet or ICMP black hole.
HE_PMTUD_STATE_BASE = 1,

// The SEARCHING state is the main probing state. This state is entered when
// probing for the BASE_PLPMTU completes.
HE_PMTUD_STATE_SEARCHING = 2,

// The SEARCH_COMPLETE state indicates that a search has completed. This is the
// normal maintenance state, where the PL is not probing to update the PLPMTU.
// DPLPMTUD remains in this state until either the PMTU_RAISE_TIMER expires or a
// black hole is detected.
HE_PMTUD_STATE_SEARCH_COMPLETE = 3,

// The ERROR state represents the case where either the network path is not known
// to support a PLPMTU of at least the BASE_PLPMTU size or when there is
// contradictory information about the network path that would otherwise result
// in excessive variation in the MPS signaled to the higher layer. The state
// implements a method to mitigate oscillation in the state-event engine.
HE_PMTUD_STATE_ERROR = 4,
} he_pmtud_state_t;

typedef struct he_ssl_ctx he_ssl_ctx_t;
typedef struct he_conn he_conn_t;
typedef struct he_plugin_chain he_plugin_chain_t;
typedef struct he_network_config_ipv4 he_network_config_ipv4_t;

/**
* @brief Data structure to hold all the state needed as a Helium client
*
*/
typedef struct he_client {
he_ssl_ctx_t *ssl_ctx;
Expand Down Expand Up @@ -468,6 +504,37 @@ typedef he_return_code_t (*he_populate_network_config_ipv4_cb_t)(he_conn_t *conn
he_network_config_ipv4_t *config,
void *context);

/**
* @brief The prototype for the Path MTU Discovery (PMTUD) time callback function
* @param conn A pointer to the connection that triggered this callback
* @param timeout The number of milliseconds to wait before calling the he_conn_pmtud_timeout
* function. If the timeout value is 0, the host application should cancel the timer.
* @param context A pointer to the user defined context
* @see he_conn_set_context Sets the value of the context pointer
*
* Lightway Path MTU Discovery needs to be able to resend probe messages if they are not received in
* time. As Lightway Core does not have its own threads or timers, it is up to the host application
* to tell Lightway Core when a certain amount of time has passed.
*
* The host application must register this callback to enable Path MTU discovery.
*
* @note Any pending timers should be reset with the value provided in the callback and there should
* only ever be one timer per connection context.
*/
typedef he_return_code_t (*he_pmtud_time_cb_t)(he_conn_t *conn, int timeout, void *context);

/**
* @brief The prototype for Lightway PMTUD state callback function
* @param conn A pointer to the connection that triggered this callback
* @param state The state that Lightway PMTUD has just entered
* @param context A pointer to the user defined context
* @see he_conn_set_context Sets the value of the context pointer
*
* Whenever Lightway PMTUD changes state, this function will be called.
*/
typedef he_return_code_t (*he_pmtud_state_change_cb_t)(he_conn_t *conn, he_pmtud_state_t state,
void *context);

typedef struct he_network_config_ipv4 {
char local_ip[HE_MAX_IPV4_STRING_LENGTH];
char peer_ip[HE_MAX_IPV4_STRING_LENGTH];
Expand Down Expand Up @@ -981,6 +1048,21 @@ bool he_ssl_ctx_is_auth_cb_set(he_ssl_ctx_t *ctx);
void he_ssl_ctx_set_populate_network_config_ipv4_cb(
he_ssl_ctx_t *ctx, he_populate_network_config_ipv4_cb_t pop_network_cb);

/**
* @brief Sets te function that will be called when Lightway PMTUD changes state
* @param ctx A pointer to a valid SSL context
* @param pmtud_state_change_cb The function to be called when Lightway PMTUD changes state
*/
void he_ssl_ctx_set_pmtud_state_change_cb(he_ssl_ctx_t *ctx,
he_pmtud_state_change_cb_t pmtud_state_change_cb);

/**
* @brief Sets te function that will be called when Lightway PMTUD needs to start the timer
* @param ctx A pointer to a valid SSL context
* @param pmtud_time_cb The function to be called when Lightway PMTUD needs to start the time
*/
void he_ssl_ctx_set_pmtud_time_cb(he_ssl_ctx_t *ctx, he_pmtud_time_cb_t pmtud_time_cb);

/**
* @brief Disables session roaming and removes the session ID from the packet header
* @return HE_SUCCESS
Expand Down
2 changes: 2 additions & 0 deletions src/he/conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ he_return_code_t he_internal_conn_configure(he_conn_t *conn, he_ssl_ctx_t *ctx)
conn->auth_buf_cb = ctx->auth_buf_cb;
conn->auth_token_cb = ctx->auth_token_cb;
conn->populate_network_config_ipv4_cb = ctx->populate_network_config_ipv4_cb;
conn->pmtud_time_cb = ctx->pmtud_time_cb;
conn->pmtud_state_change_cb = ctx->pmtud_state_change_cb;

// Copy the RNG to allow for generation of session IDs
conn->wolf_rng = ctx->wolf_rng;
Expand Down
2 changes: 1 addition & 1 deletion src/he/conn.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* *
/**
* Lightway Core
* Copyright (C) 2021 Express VPN International Ltd.
*
Expand Down
6 changes: 6 additions & 0 deletions src/he/he_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ struct he_ssl_ctx {
he_auth_token_cb_t auth_token_cb;
// Callback for populating the network config (server-only)
he_populate_network_config_ipv4_cb_t populate_network_config_ipv4_cb;
// Callback for pmtud
he_pmtud_time_cb_t pmtud_time_cb;
he_pmtud_state_change_cb_t pmtud_state_change_cb;
/// Don't send session ID in packet header
bool disable_roaming_connections;
/// Which padding type to use
Expand Down Expand Up @@ -215,6 +218,9 @@ struct he_conn {
he_auth_buf_cb_t auth_buf_cb;
// Callback for populating the network config (server-only)
he_populate_network_config_ipv4_cb_t populate_network_config_ipv4_cb;
// Callback for pmtud
he_pmtud_time_cb_t pmtud_time_cb;
he_pmtud_state_change_cb_t pmtud_state_change_cb;

/// Connection version -- set on client side, accepted on server side
he_version_info_t protocol_version;
Expand Down
33 changes: 0 additions & 33 deletions src/he/pmtud.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,39 +38,6 @@
(HE_MAX_WIRE_MTU - HE_IPV4_HEADER_SIZE - HE_UDP_HEADER_SIZE - sizeof(he_wire_hdr_t) - \
HE_WOLF_MAX_HEADER_SIZE - sizeof(he_msg_data_t))

typedef enum he_pmtud_state {
// The DISABLED state is the initial state before probing has started.
// It is also entered from any other state, when the PL indicates loss of
// connectivity. This state is left once the PL indicates connectivity to the
// remote PL. When transitioning to the BASE state, a probe packet of size
// BASE_PLPMTU can be sent immediately
HE_PMTUD_STATE_DISABLED = 0,

// The BASE state is used to confirm that the BASE_PLPMTU size is supported by
// the network path and is designed to allow an application to continue working
// when there are transient reductions in the actual PMTU. It also seeks to avoid
// long periods when a sender searching for a larger PLPMTU is unaware that
// packets are not being delivered due to a packet or ICMP black hole.
HE_PMTUD_STATE_BASE = 1,

// The SEARCHING state is the main probing state. This state is entered when
// probing for the BASE_PLPMTU completes.
HE_PMTUD_STATE_SEARCHING = 2,

// The SEARCH_COMPLETE state indicates that a search has completed. This is the
// normal maintenance state, where the PL is not probing to update the PLPMTU.
// DPLPMTUD remains in this state until either the PMTU_RAISE_TIMER expires or a
// black hole is detected.
HE_PMTUD_STATE_SEARCH_COMPLETE = 3,

// The ERROR state represents the case where either the network path is not known
// to support a PLPMTU of at least the BASE_PLPMTU size or when there is
// contradictory information about the network path that would otherwise result
// in excessive variation in the MPS signaled to the higher layer. The state
// implements a method to mitigate oscillation in the state-event engine.
HE_PMTUD_STATE_ERROR = 4,
} he_pmtud_state_t;

// Internal functions for PMTUD

/**
Expand Down
19 changes: 19 additions & 0 deletions src/he/ssl_ctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,25 @@ void he_ssl_ctx_set_populate_network_config_ipv4_cb(
ctx->populate_network_config_ipv4_cb = pop_network_cb;
}

void he_ssl_ctx_set_pmtud_time_cb(he_ssl_ctx_t *ctx, he_pmtud_time_cb_t pmtud_time_cb) {
// Return if ctx is null
if(!ctx) {
return;
}

ctx->pmtud_time_cb = pmtud_time_cb;
}

void he_ssl_ctx_set_pmtud_state_change_cb(he_ssl_ctx_t *ctx,
he_pmtud_state_change_cb_t pmtud_state_change_cb) {
// Return if ctx is null
if(!ctx) {
return;
}

ctx->pmtud_state_change_cb = pmtud_state_change_cb;
}

he_return_code_t he_ssl_ctx_set_disable_roaming(he_ssl_ctx_t *ctx) {
// Return if ctx is null
if(!ctx) {
Expand Down
16 changes: 15 additions & 1 deletion src/he/ssl_ctx.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* *
/**
* Lightway Core
* Copyright (C) 2021 Express VPN International Ltd.
*
Expand Down Expand Up @@ -470,6 +470,20 @@ bool he_ssl_ctx_is_auth_cb_set(he_ssl_ctx_t *ctx);
void he_ssl_ctx_set_populate_network_config_ipv4_cb(
he_ssl_ctx_t *ctx, he_populate_network_config_ipv4_cb_t pop_network_cb);

/**
* @brief Sets te function that will be called when Lightway PMTUD changes state
* @param ctx A pointer to a valid SSL context
* @param pmtud_state_change_cb The function to be called when Lightway PMTUD changes state
*/
void he_ssl_ctx_set_pmtud_state_change_cb(he_ssl_ctx_t *ctx,
he_pmtud_state_change_cb_t pmtud_state_change_cb);
/**
* @brief Sets te function that will be called when Lightway PMTUD needs to start the timer
* @param ctx A pointer to a valid SSL context
* @param pmtud_time_cb The function to be called when Lightway PMTUD needs to start the time
*/
void he_ssl_ctx_set_pmtud_time_cb(he_ssl_ctx_t *ctx, he_pmtud_time_cb_t pmtud_time_cb);

/**
* @brief Disables session roaming and removes the session ID from the packet header
* @return HE_SUCCESS
Expand Down
4 changes: 4 additions & 0 deletions test/he/test_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -1484,6 +1484,8 @@ void test_he_internal_conn_configure_no_version(void) {
ssl_ctx.outside_write_cb = (he_outside_write_cb_t)0x7;
ssl_ctx.network_config_ipv4_cb = (he_network_config_ipv4_cb_t)0x8;
ssl_ctx.populate_network_config_ipv4_cb = (he_populate_network_config_ipv4_cb_t)0x9;
ssl_ctx.pmtud_time_cb = (he_pmtud_time_cb_t)0x10;
ssl_ctx.pmtud_state_change_cb = (he_pmtud_state_change_cb_t)0x11;

memset(&ssl_ctx.wolf_rng, 1, sizeof(WC_RNG));

Expand Down Expand Up @@ -1511,6 +1513,8 @@ void test_he_internal_conn_configure_no_version(void) {
TEST_ASSERT_EQUAL(conn.outside_write_cb, ssl_ctx.outside_write_cb);
TEST_ASSERT_EQUAL(conn.network_config_ipv4_cb, ssl_ctx.network_config_ipv4_cb);
TEST_ASSERT_EQUAL(conn.populate_network_config_ipv4_cb, ssl_ctx.populate_network_config_ipv4_cb);
TEST_ASSERT_EQUAL(conn.pmtud_time_cb, ssl_ctx.pmtud_time_cb);
TEST_ASSERT_EQUAL(conn.pmtud_state_change_cb, ssl_ctx.pmtud_state_change_cb);

TEST_ASSERT_EQUAL(0, memcmp(&conn.wolf_rng, &ssl_ctx.wolf_rng, sizeof(WC_RNG)));
}
Expand Down
10 changes: 10 additions & 0 deletions test/he/test_ssl_ctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,16 @@ void test_set_populate_network_config_cb(void) {
TEST_ASSERT_EQUAL(pop_network_config_cb, ctx->populate_network_config_ipv4_cb);
}

void test_set_pmtud_time_cb(void) {
he_ssl_ctx_set_pmtud_time_cb(ctx, pmtud_time_cb);
TEST_ASSERT_EQUAL(pmtud_time_cb, ctx->pmtud_time_cb);
}

void test_set_pmtud_state_change_cb(void) {
he_ssl_ctx_set_pmtud_state_change_cb(ctx, pmtud_state_change_cb);
TEST_ASSERT_EQUAL(pmtud_state_change_cb, ctx->pmtud_state_change_cb);
}

void test_set_server_cert_nulls(void) {
int res = he_ssl_ctx_set_server_cert_key_files(ctx, good_username, NULL);
TEST_ASSERT_EQUAL(HE_ERR_NULL_POINTER, res);
Expand Down
10 changes: 10 additions & 0 deletions test/support/test_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ he_return_code_t pop_network_config_cb(he_conn_t *conn, he_network_config_ipv4_t
return HE_SUCCESS;
}

he_return_code_t pmtud_time_cb(he_conn_t *conn, int timeout, void *context) {
call_counter++;
return HE_SUCCESS;
}

he_return_code_t pmtud_state_change_cb(he_conn_t *conn, he_pmtud_state_t state, void *context) {
call_counter++;
return HE_SUCCESS;
}

he_return_code_t stub_overflow_plugin(he_plugin_chain_t *chain, uint8_t *packet, size_t *length,
size_t capacity, int numCalls) {
*length = capacity + 1;
Expand Down

0 comments on commit d9132fe

Please sign in to comment.