From dc85dae67ff8afcce2bb07cdbd7bf1750525820a Mon Sep 17 00:00:00 2001 From: James Yonan Date: Tue, 27 Jul 2010 07:10:01 +0000 Subject: Fixed an issue where application payload transmissions on the TLS control channel (such as AUTH_FAILED) that occur during or immediately after a TLS renegotiation might be dropped. Version 2.1.1n git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@6350 e7ae566f-a301-0410-adde-c780ea21d3b5 --- buffer.c | 34 ++++++++++++++++++++++++++-------- buffer.h | 2 ++ ssl.c | 22 ++++++++++++++++++++++ ssl.h | 2 ++ syshead.h | 4 +--- version.m4 | 2 +- 6 files changed, 54 insertions(+), 12 deletions(-) diff --git a/buffer.c b/buffer.c index c7a42fb..5108429 100644 --- a/buffer.c +++ b/buffer.c @@ -896,8 +896,11 @@ buffer_list_new (const int max_size) void buffer_list_free (struct buffer_list *ol) { - buffer_list_reset (ol); - free (ol); + if (ol) + { + buffer_list_reset (ol); + free (ol); + } } bool @@ -924,9 +927,21 @@ buffer_list_reset (struct buffer_list *ol) void buffer_list_push (struct buffer_list *ol, const unsigned char *str) { - if (!ol->max_size || ol->size < ol->max_size) + if (str) + { + const size_t len = strlen ((const char *)str); + struct buffer_entry *e = buffer_list_push_data (ol, str, len+1); + if (e) + e->buf.len = len; /* Don't count trailing '\0' as part of length */ + } +} + +struct buffer_entry * +buffer_list_push_data (struct buffer_list *ol, const uint8_t *data, size_t size) +{ + struct buffer_entry *e = NULL; + if (data && (!ol->max_size || ol->size < ol->max_size)) { - struct buffer_entry *e; ALLOC_OBJ_CLEAR (e, struct buffer_entry); ++ol->size; @@ -940,15 +955,18 @@ buffer_list_push (struct buffer_list *ol, const unsigned char *str) ASSERT (!ol->head); ol->head = e; } - e->buf = string_alloc_buf ((const char *) str, NULL); + e->buf = alloc_buf (size); + memcpy (e->buf.data, data, size); + e->buf.len = (int)size; ol->tail = e; } + return e; } struct buffer * buffer_list_peek (struct buffer_list *ol) { - if (ol->head) + if (ol && ol->head) return &ol->head->buf; else return NULL; @@ -993,10 +1011,10 @@ buffer_list_aggregate (struct buffer_list *bl, const size_t max) } } -static void +void buffer_list_pop (struct buffer_list *ol) { - if (ol->head) + if (ol && ol->head) { struct buffer_entry *e = ol->head->next; free_buf (&ol->head->buf); diff --git a/buffer.h b/buffer.h index 9351c4e..0f22cda 100644 --- a/buffer.h +++ b/buffer.h @@ -851,8 +851,10 @@ bool buffer_list_defined (const struct buffer_list *ol); void buffer_list_reset (struct buffer_list *ol); void buffer_list_push (struct buffer_list *ol, const unsigned char *str); +struct buffer_entry *buffer_list_push_data (struct buffer_list *ol, const uint8_t *data, size_t size); struct buffer *buffer_list_peek (struct buffer_list *ol); void buffer_list_advance (struct buffer_list *ol, int n); +void buffer_list_pop (struct buffer_list *ol); void buffer_list_aggregate (struct buffer_list *bl, const size_t max); diff --git a/ssl.c b/ssl.c index 9801b0e..a140641 100644 --- a/ssl.c +++ b/ssl.c @@ -2266,6 +2266,7 @@ key_state_free (struct key_state *ks, bool clear) free_buf (&ks->plaintext_read_buf); free_buf (&ks->plaintext_write_buf); free_buf (&ks->ack_write_buf); + buffer_list_free(ks->paybuf); if (ks->send_reliable) { @@ -3064,6 +3065,17 @@ key_source2_read (struct key_source2 *k2, return 1; } +static void +flush_payload_buffer (struct tls_multi *multi, struct key_state *ks) +{ + struct buffer *b; + while ((b = buffer_list_peek (ks->paybuf))) + { + key_state_write_plaintext_const (multi, ks, b->data, b->len); + buffer_list_pop (ks->paybuf); + } +} + /* * Macros for key_state_soft_reset & tls_process */ @@ -3978,6 +3990,9 @@ tls_process (struct tls_multi *multi, /* Set outgoing address for data channel packets */ link_socket_set_outgoing_addr (NULL, to_link_socket_info, &ks->remote_addr, session->common_name, session->opt->es); + /* Flush any payload packets that were buffered before our state transitioned to S_ACTIVE */ + flush_payload_buffer (multi, ks); + #ifdef MEASURE_TLS_HANDSHAKE_STATS show_tls_performance_stats(); #endif @@ -5077,6 +5092,13 @@ tls_send_payload (struct tls_multi *multi, if (key_state_write_plaintext_const (multi, ks, data, size) == 1) ret = true; } + else + { + if (!ks->paybuf) + ks->paybuf = buffer_list_new (0); + buffer_list_push_data (ks->paybuf, data, (size_t)size); + ret = true; + } ERR_clear_error (); diff --git a/ssl.h b/ssl.h index e895bb2..c6a5627 100644 --- a/ssl.h +++ b/ssl.h @@ -376,6 +376,8 @@ struct key_state struct reliable *rec_reliable; /* order incoming ciphertext packets before we pass to TLS */ struct reliable_ack *rec_ack; /* buffers all packet IDs we want to ACK back to sender */ + struct buffer_list *paybuf; + int n_bytes; /* how many bytes sent/recvd since last key exchange */ int n_packets; /* how many packets sent/recvd since last key exchange */ diff --git a/syshead.h b/syshead.h index d2ea8de..15445fc 100644 --- a/syshead.h +++ b/syshead.h @@ -531,11 +531,9 @@ socket_defined (const socket_descriptor_t sd) #endif /* - * Don't compile the struct buffer_list code unless something needs it + * Compile the struct buffer_list code */ -#if defined(ENABLE_MANAGEMENT) || defined(ENABLE_PF) #define ENABLE_BUFFER_LIST -#endif /* * Do we have pthread capability? diff --git a/version.m4 b/version.m4 index b6d1f61..be40252 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.1m]) +define(PRODUCT_VERSION,[2.1.1n]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit v1.2.3