From: Amaury Denoyelle Date: Fri, 19 Jul 2024 15:39:04 +0000 (+0200) Subject: MINOR: quic: implement reject quic-initial action X-Git-Tag: v3.1-dev5~78 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=69d7e9f3b7435d0dba4b0277804300fc8654a6cb;p=thirdparty%2Fhaproxy.git MINOR: quic: implement reject quic-initial action Define a new quic-initial action named "reject". Contrary to dgram-drop, the client is notified of the rejection by a CONNECTION_CLOSE with CONNECTION_REFUSED error code. To be able to emit the necessary CONNECTION_CLOSE frame, quic_conn is instantiated, contrary to dgram-drop action. quic_set_connection_close() is called immediatly after qc_new_conn() which prevents the handshake startup. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 0af6bb04fd..022712df25 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -11009,6 +11009,7 @@ quic-initial [ { if | unless } ] minimal list of actions is supported : - accept - dgram-drop + - reject rate-limit sessions @@ -14374,7 +14375,7 @@ expect-netscaler-cip - X - - - - - expect-proxy layer4 - X - - - - - - normalize-uri - - - - - X - - redirect - - - - - X X - -reject - X X X X X - - +reject X X X X X X - - replace-header - - - - - X X X replace-path - - - - - X - - replace-pathq - - - - - X - - @@ -14932,7 +14933,7 @@ redirect reject Usable in: QUIC Ini| TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft - - | X | X | X | X | X | - | - + X | X | X | X | X | X | - | - This stops the evaluation of the rules and immediately closes the connection without sending any response. For HTTP rules, it acts similarly to the @@ -14955,6 +14956,10 @@ reject information from leaking, typically after inspecting contents in conjunction with the "wait-for-body" action. + This action can also be used in "quic-initial" rules. The newly opened QUIC + connection is immediately closed without any SSL handshake processing and the + client is notified via a CONNECTION_REFUSED error code. + replace-header Usable in: QUIC Ini| TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft diff --git a/include/haproxy/quic_sock-t.h b/include/haproxy/quic_sock-t.h index 631cd3e106..ed396b1805 100644 --- a/include/haproxy/quic_sock-t.h +++ b/include/haproxy/quic_sock-t.h @@ -26,6 +26,8 @@ struct quic_receiver_buf { struct mt_list rxbuf_el; /* list element into receiver.rxbuf_list. */ }; +#define QUIC_DGRAM_FL_REJECT 0x00000001 + /* QUIC datagram */ struct quic_dgram { enum obj_type obj_type; @@ -40,6 +42,8 @@ struct quic_dgram { struct list recv_list; /* element pointing to quic_receiver_buf . */ struct mt_list handler_list; /* element pointing to quic_dghdlr . */ + + int flags; /* QUIC_DGRAM_FL_* values */ }; /* QUIC datagram handler */ diff --git a/src/quic_rules.c b/src/quic_rules.c index 9798424330..103833cf85 100644 --- a/src/quic_rules.c +++ b/src/quic_rules.c @@ -92,6 +92,23 @@ static enum act_parse_ret parse_dgram_drop(const char **args, int *orig_arg, return ACT_RET_PRS_OK; } +static enum act_return quic_init_action_reject(struct act_rule *rule, struct proxy *px, + struct session *sess, struct stream *s, int flags) +{ + struct quic_dgram *dgram = __objt_dgram(sess->origin); + dgram->flags |= QUIC_DGRAM_FL_REJECT; + return ACT_RET_DONE; +} + +static enum act_parse_ret parse_reject(const char **args, int *orig_arg, + struct proxy *px, + struct act_rule *rule, char **err) +{ + rule->action = ACT_CUSTOM; + rule->action_ptr = quic_init_action_reject; + return ACT_RET_PRS_OK; +} + /* List head of all known action keywords for "quic-initial" */ struct action_kw_list quic_init_actions_list = { .list = LIST_HEAD_INIT(quic_init_actions_list.list) @@ -111,6 +128,7 @@ struct action_kw *action_quic_init_custom(const char *kw) static struct action_kw_list quic_init_actions = { ILH, { { "accept", parse_accept, 0 }, { "dgram-drop", parse_dgram_drop, 0 }, + { "reject", parse_reject, 0 }, { /* END */ }, } }; diff --git a/src/quic_rx.c b/src/quic_rx.c index fc1a4acd98..3f77078c03 100644 --- a/src/quic_rx.c +++ b/src/quic_rx.c @@ -1612,20 +1612,22 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt, goto err; } - if (!pkt->token_len && - ((l->bind_conf->options & BC_O_QUIC_FORCE_RETRY) || - HA_ATOMIC_LOAD(&prx_counters->half_open_conn) >= global.tune.quic_retry_threshold)) { + /* No need to emit Retry if connection is refused. */ + if (!pkt->token_len && !(dgram->flags & QUIC_DGRAM_FL_REJECT)) { + if ((l->bind_conf->options & BC_O_QUIC_FORCE_RETRY) || + HA_ATOMIC_LOAD(&prx_counters->half_open_conn) >= global.tune.quic_retry_threshold) { + + TRACE_PROTO("Initial without token, sending retry", + QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version); + if (send_retry(l->rx.fd, &dgram->saddr, pkt, pkt->version)) { + TRACE_ERROR("Error during Retry generation", + QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version); + goto out; + } - TRACE_PROTO("Initial without token, sending retry", - QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version); - if (send_retry(l->rx.fd, &dgram->saddr, pkt, pkt->version)) { - TRACE_ERROR("Error during Retry generation", - QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version); + HA_ATOMIC_INC(&prx_counters->retry_sent); goto out; } - - HA_ATOMIC_INC(&prx_counters->retry_sent); - goto out; } /* RFC 9000 7.2. Negotiating Connection IDs: @@ -1679,6 +1681,9 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt, eb64_insert(qc->cids, &conn_id->seq_num); /* Initialize the next CID sequence number to be used for this connection. */ qc->next_cid_seq_num = 1; + + if (dgram->flags & QUIC_DGRAM_FL_REJECT) + quic_set_connection_close(qc, quic_err_transport(QC_ERR_CONNECTION_REFUSED)); } if (*new_tid != -1)