return rv;
}
+/*
+ * Place an ECH status string into a trash buffer
+ * ECH status string examples:
+ * SSL_ECH_STATUS_GREASE
+ * SSL_ECH_STATUS_NOT_TRIED
+ * SSL_ECH_STATUS_SUCCESS
+ * The status values are those defined in <openssl/ech.h>
+ * as the define'd returns from `SSL_ech_get1_status()`
+ */
+int conn_get_ech_status(struct connection *conn, struct buffer *buf)
+{
+ struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
+ char *sni_ech = NULL;
+ char *sni_clr = NULL;
+ const char *lstr = NULL;
+
+ if (!ctx)
+ return 0;
+#define s(x) #x
+ switch (SSL_ech_get1_status(ctx->ssl, &sni_ech, &sni_clr)) {
+ case SSL_ECH_STATUS_SUCCESS: lstr = s(SSL_ECH_STATUS_SUCCESS); break;
+ case SSL_ECH_STATUS_NOT_TRIED: lstr = s(SSL_ECH_STATUS_NOT_TRIED); break;
+ case SSL_ECH_STATUS_FAILED: lstr = s(SSL_ECH_STATUS_FAILED); break;
+ case SSL_ECH_STATUS_BAD_NAME: lstr = s(SSL_ECH_STATUS_BAD_NAME); break;
+ case SSL_ECH_STATUS_BAD_CALL: lstr = s(SSL_ECH_STATUS_BAD_CALL); break;
+ case SSL_ECH_STATUS_GREASE: lstr = s(SSL_ECH_STATUS_GREASE); break;
+ case SSL_ECH_STATUS_BACKEND: lstr = s(SSL_ECH_STATUS_BACKEND); break;
+ default: lstr = ""; break;
+ }
+#undef s
+ chunk_printf(buf, "%s", lstr);
+ OPENSSL_free(sni_ech);
+ OPENSSL_free(sni_clr);
+ return 1;
+}
+
+/* If ECH succeeded, return the outer SNI value seen */
+int conn_get_ech_outer_sni(struct connection *conn, struct buffer *buf)
+{
+ struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
+ char *sni_ech = NULL;
+ char *sni_clr = NULL;
+
+ if (!ctx)
+ return 0;
+ if (SSL_ech_get1_status(ctx->ssl, &sni_ech, &sni_clr)
+ == SSL_ECH_STATUS_SUCCESS && sni_clr != NULL)
+ chunk_printf(buf, "%s", sni_clr);
+ OPENSSL_free(sni_ech);
+ OPENSSL_free(sni_clr);
+ return 1;
+}
static int bind_parse_ech(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
INITCALL1(STG_REGISTER, bind_register_keywords, &bind_kws);
+
#endif
#include <haproxy/stconn.h>
#include <haproxy/tools.h>
#include <haproxy/vars.h>
+#ifdef USE_ECH
+#include <haproxy/ech.h>
+#endif
/***** Below are some sample fetching functions for ACL/patterns *****/
#endif
}
+#ifdef USE_ECH
+static int
+smp_fetch_ssl_fc_ech_status(const struct arg *args, struct sample *smp,
+ const char *kw, void *private)
+{
+ struct buffer *smp_trash;
+ struct connection *conn;
+
+ smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
+ smp->data.type = SMP_T_STR;
+ conn = objt_conn(smp->sess->origin);
+ if (!conn)
+ return 0;
+ smp_trash = get_trash_chunk();
+ if (conn_get_ech_status(conn, smp_trash) == 1) {
+ smp->data.u.str.area = smp_trash->area;
+ smp->data.u.str.data = smp_trash->data;
+ }
+ return 1;
+}
+
+static int
+smp_fetch_ssl_fc_ech_outer_sni(const struct arg *args, struct sample *smp,
+ const char *kw, void *private)
+{
+ struct buffer *smp_trash;
+ struct connection *conn;
+
+ smp->flags = SMP_F_VOL_SESS | SMP_F_CONST;
+ smp->data.type = SMP_T_STR;
+ conn = objt_conn(smp->sess->origin);
+ if (!conn)
+ return 0;
+ smp_trash = get_trash_chunk();
+ if (conn_get_ech_outer_sni(conn, smp_trash) == 1) {
+ smp->data.u.str.area = smp_trash->area;
+ smp->data.u.str.data = smp_trash->data;
+ }
+ return 1;
+}
+#endif
+
/* binary, returns tls client hello cipher list.
* Arguments: filter_option (0,1)
*/
#endif
{ "ssl_fc_sni", smp_fetch_ssl_fc_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
+#ifdef USE_ECH
+ { "ssl_fc_ech_status", smp_fetch_ssl_fc_ech_status, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
+ { "ssl_fc_ech_outer_sni", smp_fetch_ssl_fc_ech_outer_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
+#endif
{ "ssl_fc_cipherlist_bin", smp_fetch_ssl_fc_cl_bin, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
{ "ssl_fc_cipherlist_hex", smp_fetch_ssl_fc_cl_hex, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_USE_L5CLI },
{ "ssl_fc_cipherlist_str", smp_fetch_ssl_fc_cl_str, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },