From b4babf0bdfec0bb787c92115caa183236cbcc9a5 Mon Sep 17 00:00:00 2001 From: huitema <huitema@huitema.net> Date: Sat, 1 Dec 2018 19:13:20 -0800 Subject: [PATCH] Implement padding policy support --- picoquic/picoquic.h | 5 +++ picoquic/picoquic_internal.h | 7 +++- picoquic/quicctx.c | 24 +++++++++++++ picoquic/sender.c | 69 ++++++++++++++++++++++++++---------- 4 files changed, 85 insertions(+), 20 deletions(-) diff --git a/picoquic/picoquic.h b/picoquic/picoquic.h index 9f714493..a83bb794 100644 --- a/picoquic/picoquic.h +++ b/picoquic/picoquic.h @@ -348,6 +348,8 @@ int picoquic_set_verify_certificate_callback(picoquic_quic_t* quic, picoquic_ver /* Set client authentication in TLS (if enabled, client is required to send certificates). */ void picoquic_set_client_authentication(picoquic_quic_t* quic, int client_authentication); +/* Set default padding policy for the context */ + /* Connection context creation and registration */ picoquic_cnx_t* picoquic_create_cnx(picoquic_quic_t* quic, picoquic_connection_id_t initial_cnx_id, picoquic_connection_id_t remote_cnx_id, @@ -380,6 +382,9 @@ picoquic_cnx_t* picoquic_get_earliest_cnx_to_wake(picoquic_quic_t* quic, uint64_ picoquic_state_enum picoquic_get_cnx_state(picoquic_cnx_t* cnx); +void picoquic_cnx_set_padding_policy(picoquic_cnx_t * cnx, uint32_t padding_multiple, uint32_t padding_minsize); +void picoquic_cnx_get_padding_policy(picoquic_cnx_t * cnx, uint32_t * padding_multiple, uint32_t * padding_minsize); + int picoquic_tls_is_psk_handshake(picoquic_cnx_t* cnx); int picoquic_tls_is_early_data_skipped(picoquic_cnx_t* cnx); diff --git a/picoquic/picoquic_internal.h b/picoquic/picoquic_internal.h index 3d4c0ea8..eb6a982c 100644 --- a/picoquic/picoquic_internal.h +++ b/picoquic/picoquic_internal.h @@ -313,8 +313,9 @@ typedef struct st_picoquic_quic_t { char const* ticket_file_name; picoquic_stored_ticket_t* p_first_ticket; uint32_t mtu_max; - uint32_t flags; + uint32_t padding_multiple_default; + uint32_t padding_minsize_default; picoquic_stateless_packet_t* pending_stateless_packet; @@ -623,6 +624,10 @@ typedef struct st_picoquic_cnx_t { /* Local and remote parameters */ picoquic_tp_t local_parameters; picoquic_tp_t remote_parameters; + /* Padding policy */ + uint32_t padding_multiple; + uint32_t padding_minsize; + /* On clients, document the SNI and ALPN expected from the server */ /* TODO: there may be a need to propose multiple ALPN */ char const* sni; diff --git a/picoquic/quicctx.c b/picoquic/quicctx.c index e1168ed5..ab72d6c8 100644 --- a/picoquic/quicctx.c +++ b/picoquic/quicctx.c @@ -203,6 +203,8 @@ picoquic_quic_t* picoquic_create(uint32_t nb_connections, quic->cnx_id_callback_ctx = cnx_id_callback_ctx; quic->p_simulated_time = p_simulated_time; quic->local_ctx_length = 8; /* TODO: should be lower on clients-only implementation */ + quic->padding_multiple_default = 0; /* TODO: consider default = 128 */ + quic->padding_minsize_default = PICOQUIC_RESET_PACKET_MIN_SIZE; if (cnx_id_callback != NULL) { quic->flags |= picoquic_context_unconditional_cnx_id; @@ -273,6 +275,12 @@ int picoquic_set_default_tp(picoquic_quic_t* quic, picoquic_tp_t * tp) return ret; } +void picoquic_set_default_padding(picoquic_quic_t* quic, uint32_t padding_multiple, uint32_t padding_minsize) +{ + quic->padding_minsize_default = padding_minsize; + quic->padding_multiple_default = padding_multiple; +} + void picoquic_free(picoquic_quic_t* quic) { if (quic != NULL) { @@ -1326,6 +1334,10 @@ picoquic_cnx_t* picoquic_create_cnx(picoquic_quic_t* quic, cnx->max_stream_id_bidir_remote = (cnx->client_mode)?4:0; cnx->max_stream_id_unidir_remote = 0; + /* Initialize padding policy to default for context */ + cnx->padding_multiple = quic->padding_multiple_default; + cnx->padding_minsize = quic->padding_minsize_default; + if (sni != NULL) { cnx->sni = picoquic_string_duplicate(sni); } @@ -1560,6 +1572,18 @@ uint64_t picoquic_is_0rtt_available(picoquic_cnx_t* cnx) return (cnx->crypto_context[1].aead_encrypt == NULL) ? 0 : 1; } +void picoquic_cnx_set_padding_policy(picoquic_cnx_t * cnx, uint32_t padding_multiple, uint32_t padding_minsize) +{ + cnx->padding_multiple = padding_multiple; + cnx->padding_minsize = padding_minsize; +} + +void picoquic_cnx_get_padding_policy(picoquic_cnx_t * cnx, uint32_t * padding_multiple, uint32_t * padding_minsize) +{ + *padding_multiple = cnx->padding_multiple; + *padding_minsize = cnx->padding_minsize; +} + /* * Provide clock time */ diff --git a/picoquic/sender.c b/picoquic/sender.c index 065bbf54..0d438f06 100644 --- a/picoquic/sender.c +++ b/picoquic/sender.c @@ -174,6 +174,43 @@ int picoquic_stop_sending(picoquic_cnx_t* cnx, return ret; } +/* + * Manage content padding + */ + +uint32_t picoquic_pad_to_target_length(uint8_t * bytes, uint32_t length, uint32_t target) +{ + if (length < target) { + memset(bytes + length, 0, target - length); + length = target; + } + + return length; +} + +uint32_t picoquic_pad_to_policy(picoquic_cnx_t * cnx, uint8_t * bytes, uint32_t length, uint32_t max_length) +{ + uint32_t target = cnx->padding_minsize; + + if (length > target && cnx->padding_multiple != 0) { + uint32_t delta = (length - target) % cnx->padding_multiple; + + if (delta == 0) { + target = length; + } + else { + target = length + cnx->padding_multiple - delta; + } + } + + if (target > max_length) { + target = max_length; + } + + return picoquic_pad_to_target_length(bytes, length, target); +} + + /* * Packet management */ @@ -874,9 +911,8 @@ int picoquic_retransmit_needed(picoquic_cnx_t* cnx, if (ret == 0 && !frame_is_pure_ack) { if (picoquic_is_stream_frame_unlimited(&p->bytes[byte_index])) { /* Need to PAD to the end of the frame to avoid sending extra bytes */ - while (checksum_length + length + frame_length < send_buffer_max) { - new_bytes[length] = picoquic_frame_type_padding; - length++; + if (checksum_length + length + frame_length < send_buffer_max) { + length = picoquic_pad_to_target_length(new_bytes, length, (uint32_t)(send_buffer_max - checksum_length - frame_length)); } } memcpy(&new_bytes[length], &p->bytes[byte_index], frame_length); @@ -1161,9 +1197,10 @@ int picoquic_prepare_packet_0rtt(picoquic_cnx_t* cnx, picoquic_path_t * path_x, } /* Add padding if required */ if (padding_required) { - while (length < send_buffer_max - checksum_overhead) { - bytes[length++] = 0; - } + length = picoquic_pad_to_target_length(bytes, length, (uint32_t)(send_buffer_max - checksum_overhead)); + } + else { + length = picoquic_pad_to_policy(cnx, bytes, length, (uint32_t)(send_buffer_max - checksum_overhead)); } } @@ -1477,10 +1514,11 @@ int picoquic_prepare_packet_client_init(picoquic_cnx_t* cnx, picoquic_path_t * p cnx->original_cnxid.id_len != 0)) { /* Pad to minimum packet length. But don't do that if the * initial packet will be coalesced with 0-RTT packet */ - while (length < send_buffer_max - checksum_overhead) { - bytes[length++] = 0; - } - } + length = picoquic_pad_to_target_length(bytes, length, (uint32_t)(send_buffer_max - checksum_overhead)); + } + else { + length = picoquic_pad_to_policy(cnx, bytes, length, (uint32_t)(send_buffer_max - checksum_overhead)); + } if (packet_type == picoquic_packet_0rtt_protected) { cnx->nb_zero_rtt_sent++; @@ -2265,12 +2303,7 @@ int picoquic_prepare_packet_ready(picoquic_cnx_t* cnx, picoquic_path_t * path_x, } if (length > header_length) { - if ((length + checksum_overhead) <= PICOQUIC_RESET_PACKET_MIN_SIZE) { - uint32_t pad_size = PICOQUIC_RESET_PACKET_MIN_SIZE - checksum_overhead - length + 1; - for (uint32_t i = 0; i < pad_size; i++) { - bytes[length++] = 0; - } - } + length = picoquic_pad_to_policy(cnx, bytes, length, (uint32_t)(send_buffer_max - checksum_overhead)); } else if (ret == 0 && send_buffer_max > path_x->send_mtu && path_x->cwin > path_x->bytes_in_transit && picoquic_is_mtu_probe_needed(cnx, path_x)) { @@ -2497,9 +2530,7 @@ int picoquic_prepare_probe(picoquic_cnx_t* cnx, /* Pack to min length, to verify that the path can carry a min length packet */ if (length + checksum_overhead < PICOQUIC_INITIAL_MTU_IPV6) { - uint32_t pad_size = PICOQUIC_INITIAL_MTU_IPV6 - checksum_overhead - length; - memset(&bytes[length], 0, pad_size); - length += pad_size; + length = picoquic_pad_to_target_length(bytes, length, PICOQUIC_INITIAL_MTU_IPV6 - checksum_overhead); } /* set the return addresses */ -- GitLab