On Mon, Nov 27, 2017 at 06:19:41PM +0100, Emmanuel Hocdet wrote:
> > Maybe the best is to add a new flag per conn_stream, CS_FL_WAITING_FOR_HS or
> > something, instead of relying on CO_FL_EARLY_DATA.
> > I think I'm going to do something like that.
> 
> I think it's a good idea, two different things to deal with one tag.
> 
> > That still doesn't help with your problem with TCP mode, though. I still 
> > want
> > the CO_FL_EARLY_DATA to be removed after the handshake, so that we don't
> > add the "Early-Data: 1" header if it is not needed. But it just occured
> > to me that I can easily fix that by adding the header, not only if 
> > CO_FL_EARLY_DATA is set, but if CO_FL_EARLY_SSL_HS or CO_FL_SSL_WAIT_HS is 
> > set.
> > That way we will both be happy :)
> 

So, this if my first cut at it. It basically does as I said.
Only thing you may be unhappy with, I made the sample fetch ssl_fc_has_early
return 0 if we had early data but the handshake happened, because the main
use case is to know if there are early data and if they're a potential
security risk.
If you can give me a case where we have a need a sample fetch to know there
were early data, even after the handshake, maybe we can introduce a new
sample fetch, ssl_fc_has_insecure_early, or something ?

Regards,

Olivier
>From bda3b7800677184ea19fb81f75f9a9b44c79efeb Mon Sep 17 00:00:00 2001
From: Olivier Houchard <ohouch...@haproxy.com>
Date: Mon, 27 Nov 2017 18:41:32 +0100
Subject: [PATCH 1/2] MINOR: early data: Don't rely on CO_FL_EARLY_DATA to wake
 up streams.

Instead of looking for CO_FL_EARLY_DATA to know if we have to try to wake
up a stream, because it is waiting for a SSL handshake, instead add a new
conn_stream flag, CS_FL_WAIT_FOR_HS. This way we don't have to rely on
CO_FL_EARLY_DATA, and we will only wake streams that are actually waiting.
---
 include/types/connection.h |  1 +
 src/mux_h2.c               | 24 ++++++++++++++++++------
 src/ssl_sock.c             |  5 ++++-
 src/stream_interface.c     |  4 +++-
 4 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/include/types/connection.h b/include/types/connection.h
index a9d04474d..f220c42a9 100644
--- a/include/types/connection.h
+++ b/include/types/connection.h
@@ -69,6 +69,7 @@ enum {
 
        CS_FL_ERROR         = 0x00000100,  /* a fatal error was reported */
        CS_FL_EOS           = 0x00001000,  /* End of stream */
+       CS_FL_WAIT_FOR_HS   = 0x00010000,  /* This stream is waiting for 
handhskae */
 };
 
 /* cs_shutr() modes */
diff --git a/src/mux_h2.c b/src/mux_h2.c
index 4567b8ff0..4db90d4c8 100644
--- a/src/mux_h2.c
+++ b/src/mux_h2.c
@@ -54,6 +54,7 @@ static struct pool_head *pool_head_h2s;
 /* other flags */
 #define H2_CF_GOAWAY_SENT       0x00000100  // a GOAWAY frame was successfully 
sent
 #define H2_CF_GOAWAY_FAILED     0x00000200  // a GOAWAY frame failed to be sent
+#define H2_CF_WAIT_FOR_HS       0x00000400  // We did check that at least a 
stream was waiting for handshake
 
 
 /* H2 connection state, in h2c->st0 */
@@ -2091,14 +2092,25 @@ static int h2_wake(struct connection *conn)
        struct h2c *h2c = conn->mux_ctx;
 
        /*
-        * If we received early data, try to wake any stream, just in case
-        * at least one of them was waiting for the handshake
+        * If we received early data, and the handshake is done, wake
+        * any stream that was waiting for it.
         */
-       if ((conn->flags & (CO_FL_EARLY_SSL_HS | CO_FL_EARLY_DATA | 
CO_FL_HANDSHAKE)) ==
-           CO_FL_EARLY_DATA) {
-               h2_wake_some_streams(h2c, 0, 0);
-               conn->flags &= ~CO_FL_EARLY_DATA;
+       if (!(h2c->flags & H2_CF_WAIT_FOR_HS) &&
+           (conn->flags & (CO_FL_EARLY_SSL_HS | CO_FL_HANDSHAKE | 
CO_FL_EARLY_DATA)) == CO_FL_EARLY_DATA) {
+               struct eb32_node *node;
+               struct h2s *h2s;
+
+               h2c->flags |= H2_CF_WAIT_FOR_HS;
+               node = eb32_lookup_ge(&h2c->streams_by_id, 1);
+
+               while (node) {
+                       h2s = container_of(node, struct h2s, by_id);
+                       if (h2s->cs->flags & CS_FL_WAIT_FOR_HS)
+                               h2s->cs->data_cb->wake(h2s->cs);
+                       node = eb32_next(node);
+               }
        }
+
        if (conn->flags & CO_FL_ERROR || conn_xprt_read0_pending(conn) ||
            h2c->st0 == H2_CS_ERROR2 || h2c->flags & H2_CF_GOAWAY_FAILED ||
            (eb_is_empty(&h2c->streams_by_id) && h2c->last_sid >= 0 &&
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index da1aecbcc..7c5fd6b10 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -8705,11 +8705,14 @@ enum act_return ssl_action_wait_for_hs(struct act_rule 
*rule, struct proxy *px,
                                        struct session *sess, struct stream *s, 
int flags)
 {
        struct connection *conn;
+       struct conn_stream *cs;
 
        conn = objt_conn(sess->origin);
+       cs = objt_cs(s->si[0].end);
 
-       if (conn) {
+       if (conn && cs) {
                if (conn->flags & (CO_FL_EARLY_SSL_HS | CO_FL_SSL_WAIT_HS)) {
+                       cs->flags |= CS_FL_WAIT_FOR_HS;
                        s->req.flags |= CF_READ_NULL;
                        return ACT_RET_YIELD;
                }
diff --git a/src/stream_interface.c b/src/stream_interface.c
index 6f9f27b98..4c2fff94c 100644
--- a/src/stream_interface.c
+++ b/src/stream_interface.c
@@ -584,7 +584,9 @@ static int si_cs_wake_cb(struct conn_stream *cs)
         * in the event there's an analyser waiting for the end of
         * the handshake.
         */
-       if ((conn->flags & (CO_FL_EARLY_DATA | CO_FL_EARLY_SSL_HS)) == 
CO_FL_EARLY_DATA) {
+       if (!(conn->flags & (CO_FL_HANDSHAKE | CO_FL_EARLY_SSL_HS)) &&
+           (cs->flags & CS_FL_WAIT_FOR_HS)) {
+               cs->flags &= ~CS_FL_WAIT_FOR_HS;
                task_wakeup(si_task(si), TASK_WOKEN_MSG);
        }
 
-- 
2.14.3

>From e697b44db0e187ae6d822f7ed163fb2696cd4b97 Mon Sep 17 00:00:00 2001
From: Olivier Houchard <ohouch...@haproxy.com>
Date: Wed, 29 Nov 2017 19:51:19 +0100
Subject: [PATCH 2/2] MINOR: early data: Never remove the CO_FL_EARLY_DATA
 flag.

It may be useful to keep the CO_FL_EARLY_DATA flag, so that we know early
data were used, so instead of doing this, only add the Early-data header,
and have the sample fetch ssl_fc_has_early return 1, if CO_FL_EARLY_DATA is
set, and if the handshake isn't done yet.
---
 src/proto_http.c | 3 ++-
 src/ssl_sock.c   | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/proto_http.c b/src/proto_http.c
index 04771b78d..48fb69e32 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -3413,7 +3413,8 @@ int http_process_req_common(struct stream *s, struct 
channel *req, int an_bit, s
                }
        }
 
-       if (conn && conn->flags & CO_FL_EARLY_DATA) {
+       if (conn && (conn->flags & CO_FL_EARLY_DATA) &&
+           (conn->flags & (CO_FL_EARLY_SSL_HS | CO_FL_HANDSHAKE))) {
                struct hdr_ctx ctx;
 
                ctx.idx = 0;
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 7c5fd6b10..d4d9dbaa7 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -6020,7 +6020,8 @@ smp_fetch_ssl_fc_has_early(const struct arg *args, struct 
sample *smp, const cha
 
        smp->flags = 0;
        smp->data.type = SMP_T_BOOL;
-       smp->data.u.sint = (conn->flags & CO_FL_EARLY_DATA) ? 1 : 0;
+       smp->data.u.sint = ((conn->flags & CO_FL_EARLY_DATA)  &&
+           (conn->flags & (CO_FL_EARLY_SSL_HS | CO_FL_HANDSHAKE))) ? 1 : 0;
 
        return 1;
 }
-- 
2.14.3

Reply via email to