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.
This commit is contained in:
Amaury Denoyelle 2024-07-19 17:39:04 +02:00
parent f91be2657e
commit 69d7e9f3b7
4 changed files with 45 additions and 13 deletions

View File

@ -11009,6 +11009,7 @@ quic-initial <action> [ { if | unless } <condition> ]
minimal list of actions is supported : minimal list of actions is supported :
- accept - accept
- dgram-drop - dgram-drop
- reject
rate-limit sessions <rate> rate-limit sessions <rate>
@ -14374,7 +14375,7 @@ expect-netscaler-cip - X - - - - -
expect-proxy layer4 - X - - - - - - expect-proxy layer4 - X - - - - - -
normalize-uri - - - - - X - - normalize-uri - - - - - X - -
redirect - - - - - X X - redirect - - - - - X X -
reject - X X X X X - - reject X X X X X X - -
replace-header - - - - - X X X replace-header - - - - - X X X
replace-path - - - - - X - - replace-path - - - - - X - -
replace-pathq - - - - - X - - replace-pathq - - - - - X - -
@ -14932,7 +14933,7 @@ redirect <rule>
reject reject
Usable in: QUIC Ini| TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft 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 This stops the evaluation of the rules and immediately closes the connection
without sending any response. For HTTP rules, it acts similarly to the 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 information from leaking, typically after inspecting contents in conjunction
with the "wait-for-body" action. 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 <name> <match-regex> <replace-fmt> replace-header <name> <match-regex> <replace-fmt>
Usable in: QUIC Ini| TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft Usable in: QUIC Ini| TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft

View File

@ -26,6 +26,8 @@ struct quic_receiver_buf {
struct mt_list rxbuf_el; /* list element into receiver.rxbuf_list. */ struct mt_list rxbuf_el; /* list element into receiver.rxbuf_list. */
}; };
#define QUIC_DGRAM_FL_REJECT 0x00000001
/* QUIC datagram */ /* QUIC datagram */
struct quic_dgram { struct quic_dgram {
enum obj_type obj_type; enum obj_type obj_type;
@ -40,6 +42,8 @@ struct quic_dgram {
struct list recv_list; /* element pointing to quic_receiver_buf <dgram_list>. */ struct list recv_list; /* element pointing to quic_receiver_buf <dgram_list>. */
struct mt_list handler_list; /* element pointing to quic_dghdlr <dgrams>. */ struct mt_list handler_list; /* element pointing to quic_dghdlr <dgrams>. */
int flags; /* QUIC_DGRAM_FL_* values */
}; };
/* QUIC datagram handler */ /* QUIC datagram handler */

View File

@ -92,6 +92,23 @@ static enum act_parse_ret parse_dgram_drop(const char **args, int *orig_arg,
return ACT_RET_PRS_OK; 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" */ /* List head of all known action keywords for "quic-initial" */
struct action_kw_list quic_init_actions_list = { struct action_kw_list quic_init_actions_list = {
.list = LIST_HEAD_INIT(quic_init_actions_list.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, { static struct action_kw_list quic_init_actions = { ILH, {
{ "accept", parse_accept, 0 }, { "accept", parse_accept, 0 },
{ "dgram-drop", parse_dgram_drop, 0 }, { "dgram-drop", parse_dgram_drop, 0 },
{ "reject", parse_reject, 0 },
{ /* END */ }, { /* END */ },
} }
}; };

View File

@ -1612,20 +1612,22 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt,
goto err; goto err;
} }
if (!pkt->token_len && /* No need to emit Retry if connection is refused. */
((l->bind_conf->options & BC_O_QUIC_FORCE_RETRY) || if (!pkt->token_len && !(dgram->flags & QUIC_DGRAM_FL_REJECT)) {
HA_ATOMIC_LOAD(&prx_counters->half_open_conn) >= global.tune.quic_retry_threshold)) { 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", TRACE_PROTO("Initial without token, sending retry",
QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version); QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version);
if (send_retry(l->rx.fd, &dgram->saddr, pkt, pkt->version)) { if (send_retry(l->rx.fd, &dgram->saddr, pkt, pkt->version)) {
TRACE_ERROR("Error during Retry generation", TRACE_ERROR("Error during Retry generation",
QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version); QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version);
goto out;
}
HA_ATOMIC_INC(&prx_counters->retry_sent);
goto out; goto out;
} }
HA_ATOMIC_INC(&prx_counters->retry_sent);
goto out;
} }
/* RFC 9000 7.2. Negotiating Connection IDs: /* 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); eb64_insert(qc->cids, &conn_id->seq_num);
/* Initialize the next CID sequence number to be used for this connection. */ /* Initialize the next CID sequence number to be used for this connection. */
qc->next_cid_seq_num = 1; 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) if (*new_tid != -1)