nghttpx: Allocate server id in Connection ID
This commit is contained in:
parent
89457fd991
commit
80cc623eb2
|
@ -455,6 +455,7 @@ typedef struct quic_hd {
|
||||||
#define MAX_DCIDLEN 20
|
#define MAX_DCIDLEN 20
|
||||||
#define MIN_DCIDLEN 8
|
#define MIN_DCIDLEN 8
|
||||||
#define CID_PREFIXLEN 8
|
#define CID_PREFIXLEN 8
|
||||||
|
#define CID_PREFIX_OFFSET 1
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
NGTCP2_PKT_INITIAL = 0x0,
|
NGTCP2_PKT_INITIAL = 0x0,
|
||||||
|
@ -579,6 +580,7 @@ int select_reuseport(struct sk_reuseport_md *reuse_md) {
|
||||||
__u8 qpktbuf[6 + MAX_DCIDLEN];
|
__u8 qpktbuf[6 + MAX_DCIDLEN];
|
||||||
struct AES_ctx aes_ctx;
|
struct AES_ctx aes_ctx;
|
||||||
__u8 key[AES_KEYLEN];
|
__u8 key[AES_KEYLEN];
|
||||||
|
__u8 *cid_prefix;
|
||||||
|
|
||||||
if (bpf_skb_load_bytes(reuse_md, sizeof(struct udphdr), qpktbuf,
|
if (bpf_skb_load_bytes(reuse_md, sizeof(struct udphdr), qpktbuf,
|
||||||
sizeof(qpktbuf)) != 0) {
|
sizeof(qpktbuf)) != 0) {
|
||||||
|
@ -615,9 +617,10 @@ int select_reuseport(struct sk_reuseport_md *reuse_md) {
|
||||||
case NGTCP2_PKT_INITIAL:
|
case NGTCP2_PKT_INITIAL:
|
||||||
case NGTCP2_PKT_0RTT:
|
case NGTCP2_PKT_0RTT:
|
||||||
if (qhd.dcidlen == SV_DCIDLEN) {
|
if (qhd.dcidlen == SV_DCIDLEN) {
|
||||||
AES_ECB_decrypt(&aes_ctx, qhd.dcid);
|
cid_prefix = qhd.dcid + CID_PREFIX_OFFSET;
|
||||||
|
AES_ECB_decrypt(&aes_ctx, cid_prefix);
|
||||||
|
|
||||||
psk_index = bpf_map_lookup_elem(&cid_prefix_map, qhd.dcid);
|
psk_index = bpf_map_lookup_elem(&cid_prefix_map, cid_prefix);
|
||||||
if (psk_index != NULL) {
|
if (psk_index != NULL) {
|
||||||
sk_index = *psk_index;
|
sk_index = *psk_index;
|
||||||
|
|
||||||
|
@ -634,9 +637,10 @@ int select_reuseport(struct sk_reuseport_md *reuse_md) {
|
||||||
return SK_DROP;
|
return SK_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
AES_ECB_decrypt(&aes_ctx, qhd.dcid);
|
cid_prefix = qhd.dcid + CID_PREFIX_OFFSET;
|
||||||
|
AES_ECB_decrypt(&aes_ctx, cid_prefix);
|
||||||
|
|
||||||
psk_index = bpf_map_lookup_elem(&cid_prefix_map, qhd.dcid);
|
psk_index = bpf_map_lookup_elem(&cid_prefix_map, cid_prefix);
|
||||||
if (psk_index == NULL) {
|
if (psk_index == NULL) {
|
||||||
sk_index = sk_index_from_dcid(&qhd, reuse_md, *pnum_socks);
|
sk_index = sk_index_from_dcid(&qhd, reuse_md, *pnum_socks);
|
||||||
|
|
||||||
|
|
|
@ -193,6 +193,7 @@ OPTIONS = [
|
||||||
"frontend-quic-require-token",
|
"frontend-quic-require-token",
|
||||||
"frontend-quic-congestion-controller",
|
"frontend-quic-congestion-controller",
|
||||||
"frontend-quic-connection-id-encryption-key",
|
"frontend-quic-connection-id-encryption-key",
|
||||||
|
"frontend-quic-server-id",
|
||||||
]
|
]
|
||||||
|
|
||||||
LOGVARS = [
|
LOGVARS = [
|
||||||
|
|
25
src/shrpx.cc
25
src/shrpx.cc
|
@ -1342,6 +1342,7 @@ int generate_cid_prefix(
|
||||||
std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>> &cid_prefixes,
|
std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>> &cid_prefixes,
|
||||||
const Config *config) {
|
const Config *config) {
|
||||||
auto &apiconf = config->api;
|
auto &apiconf = config->api;
|
||||||
|
auto &quicconf = config->quic;
|
||||||
|
|
||||||
size_t num_cid_prefix;
|
size_t num_cid_prefix;
|
||||||
if (config->single_thread) {
|
if (config->single_thread) {
|
||||||
|
@ -1360,7 +1361,8 @@ int generate_cid_prefix(
|
||||||
cid_prefixes.resize(num_cid_prefix);
|
cid_prefixes.resize(num_cid_prefix);
|
||||||
|
|
||||||
for (auto &cid_prefix : cid_prefixes) {
|
for (auto &cid_prefix : cid_prefixes) {
|
||||||
if (create_cid_prefix(cid_prefix.data()) != 0) {
|
if (create_cid_prefix(cid_prefix.data(),
|
||||||
|
quicconf.upstream.server_id.data()) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1864,6 +1866,12 @@ void fill_default_config(Config *config) {
|
||||||
assert(0);
|
assert(0);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (RAND_bytes(upstreamconf.server_id.data(),
|
||||||
|
upstreamconf.server_id.size()) != 1) {
|
||||||
|
assert(0);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &http3conf = config->http3;
|
auto &http3conf = config->http3;
|
||||||
|
@ -3253,6 +3261,14 @@ HTTP/3 and QUIC:
|
||||||
connection in a configuration reload event, old and new
|
connection in a configuration reload event, old and new
|
||||||
configuration must have this option and share the same
|
configuration must have this option and share the same
|
||||||
key.
|
key.
|
||||||
|
--frontend-quic-server-id=<HEXSTRING>
|
||||||
|
Specify server ID encoded in Connection ID to identify
|
||||||
|
this particular server instance. Connection ID is
|
||||||
|
encrypted and this part is not visible in public. It
|
||||||
|
must be 2 bytes long and must be encoded in hex string
|
||||||
|
(which is 4 bytes long). If this option is omitted, a
|
||||||
|
random server ID is generated on startup and
|
||||||
|
configuration reload.
|
||||||
--no-quic-bpf
|
--no-quic-bpf
|
||||||
Disable eBPF.
|
Disable eBPF.
|
||||||
--frontend-http3-window-size=<SIZE>
|
--frontend-http3-window-size=<SIZE>
|
||||||
|
@ -4053,6 +4069,8 @@ int main(int argc, char **argv) {
|
||||||
required_argument, &flag, 183},
|
required_argument, &flag, 183},
|
||||||
{SHRPX_OPT_FRONTEND_QUIC_CONNECTION_ID_ENCRYPTION_KEY.c_str(),
|
{SHRPX_OPT_FRONTEND_QUIC_CONNECTION_ID_ENCRYPTION_KEY.c_str(),
|
||||||
required_argument, &flag, 184},
|
required_argument, &flag, 184},
|
||||||
|
{SHRPX_OPT_FRONTEND_QUIC_SERVER_ID.c_str(), required_argument, &flag,
|
||||||
|
185},
|
||||||
{nullptr, 0, nullptr, 0}};
|
{nullptr, 0, nullptr, 0}};
|
||||||
|
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
@ -4936,6 +4954,11 @@ int main(int argc, char **argv) {
|
||||||
SHRPX_OPT_FRONTEND_QUIC_CONNECTION_ID_ENCRYPTION_KEY,
|
SHRPX_OPT_FRONTEND_QUIC_CONNECTION_ID_ENCRYPTION_KEY,
|
||||||
StringRef{optarg});
|
StringRef{optarg});
|
||||||
break;
|
break;
|
||||||
|
case 185:
|
||||||
|
// --frontend-quic-server-id
|
||||||
|
cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_SERVER_ID,
|
||||||
|
StringRef{optarg});
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2273,6 +2273,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||||
break;
|
break;
|
||||||
case 23:
|
case 23:
|
||||||
switch (name[22]) {
|
switch (name[22]) {
|
||||||
|
case 'd':
|
||||||
|
if (util::strieq_l("frontend-quic-server-i", name, 22)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_QUIC_SERVER_ID;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
if (util::strieq_l("client-private-key-fil", name, 22)) {
|
if (util::strieq_l("client-private-key-fil", name, 22)) {
|
||||||
return SHRPX_OPTID_CLIENT_PRIVATE_KEY_FILE;
|
return SHRPX_OPTID_CLIENT_PRIVATE_KEY_FILE;
|
||||||
|
@ -4036,6 +4041,17 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
||||||
optarg);
|
optarg);
|
||||||
#endif // ENABLE_HTTP3
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_FRONTEND_QUIC_SERVER_ID:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
if (optarg.size() != config->quic.upstream.server_id.size() * 2 ||
|
||||||
|
!util::is_hex_string(optarg)) {
|
||||||
|
LOG(ERROR) << opt << ": must be a hex-string";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
util::decode_hex(std::begin(config->quic.upstream.server_id), optarg);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
case SHRPX_OPTID_CONF:
|
case SHRPX_OPTID_CONF:
|
||||||
LOG(WARN) << "conf: ignored";
|
LOG(WARN) << "conf: ignored";
|
||||||
|
|
|
@ -393,6 +393,8 @@ constexpr auto SHRPX_OPT_FRONTEND_QUIC_CONGESTION_CONTROLLER =
|
||||||
StringRef::from_lit("frontend-quic-congestion-controller");
|
StringRef::from_lit("frontend-quic-congestion-controller");
|
||||||
constexpr auto SHRPX_OPT_FRONTEND_QUIC_CONNECTION_ID_ENCRYPTION_KEY =
|
constexpr auto SHRPX_OPT_FRONTEND_QUIC_CONNECTION_ID_ENCRYPTION_KEY =
|
||||||
StringRef::from_lit("frontend-quic-connection-id-encryption-key");
|
StringRef::from_lit("frontend-quic-connection-id-encryption-key");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_QUIC_SERVER_ID =
|
||||||
|
StringRef::from_lit("frontend-quic-server-id");
|
||||||
|
|
||||||
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
||||||
|
|
||||||
|
@ -764,6 +766,7 @@ struct QUICConfig {
|
||||||
bool early_data;
|
bool early_data;
|
||||||
bool require_token;
|
bool require_token;
|
||||||
std::array<uint8_t, SHRPX_QUIC_CID_ENCRYPTION_KEYLEN> cid_encryption_key;
|
std::array<uint8_t, SHRPX_QUIC_CID_ENCRYPTION_KEYLEN> cid_encryption_key;
|
||||||
|
std::array<uint8_t, SHRPX_QUIC_SERVER_IDLEN> server_id;
|
||||||
} upstream;
|
} upstream;
|
||||||
struct {
|
struct {
|
||||||
StringRef prog_file;
|
StringRef prog_file;
|
||||||
|
@ -1223,6 +1226,7 @@ enum {
|
||||||
SHRPX_OPTID_FRONTEND_QUIC_IDLE_TIMEOUT,
|
SHRPX_OPTID_FRONTEND_QUIC_IDLE_TIMEOUT,
|
||||||
SHRPX_OPTID_FRONTEND_QUIC_QLOG_DIR,
|
SHRPX_OPTID_FRONTEND_QUIC_QLOG_DIR,
|
||||||
SHRPX_OPTID_FRONTEND_QUIC_REQUIRE_TOKEN,
|
SHRPX_OPTID_FRONTEND_QUIC_REQUIRE_TOKEN,
|
||||||
|
SHRPX_OPTID_FRONTEND_QUIC_SERVER_ID,
|
||||||
SHRPX_OPTID_FRONTEND_READ_TIMEOUT,
|
SHRPX_OPTID_FRONTEND_READ_TIMEOUT,
|
||||||
SHRPX_OPTID_FRONTEND_WRITE_TIMEOUT,
|
SHRPX_OPTID_FRONTEND_WRITE_TIMEOUT,
|
||||||
SHRPX_OPTID_HEADER_FIELD_BUFFER,
|
SHRPX_OPTID_HEADER_FIELD_BUFFER,
|
||||||
|
|
|
@ -1292,9 +1292,9 @@ int ConnectionHandler::quic_ipc_read() {
|
||||||
|
|
||||||
std::array<uint8_t, SHRPX_QUIC_DECRYPTED_DCIDLEN> decrypted_dcid;
|
std::array<uint8_t, SHRPX_QUIC_DECRYPTED_DCIDLEN> decrypted_dcid;
|
||||||
|
|
||||||
if (decrypt_quic_connection_id(decrypted_dcid.data(), dcid,
|
if (decrypt_quic_connection_id(
|
||||||
quicconf.upstream.cid_encryption_key.data()) !=
|
decrypted_dcid.data(), dcid + SHRPX_QUIC_CID_PREFIX_OFFSET,
|
||||||
0) {
|
quicconf.upstream.cid_encryption_key.data()) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,30 +143,40 @@ int quic_send_packet(const UpstreamAddr *faddr, const sockaddr *remote_sa,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int generate_quic_connection_id(ngtcp2_cid &cid, size_t cidlen) {
|
int generate_quic_retry_connection_id(ngtcp2_cid &cid, size_t cidlen,
|
||||||
|
const uint8_t *server_id,
|
||||||
|
const uint8_t *key) {
|
||||||
|
assert(cidlen == SHRPX_QUIC_SCIDLEN);
|
||||||
|
|
||||||
if (RAND_bytes(cid.data, cidlen) != 1) {
|
if (RAND_bytes(cid.data, cidlen) != 1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cid.datalen = cidlen;
|
cid.datalen = cidlen;
|
||||||
|
|
||||||
return 0;
|
auto p = cid.data + SHRPX_QUIC_CID_PREFIX_OFFSET;
|
||||||
|
|
||||||
|
std::copy_n(server_id, SHRPX_QUIC_SERVER_IDLEN, p);
|
||||||
|
|
||||||
|
return encrypt_quic_connection_id(p, p, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
int generate_encrypted_quic_connection_id(ngtcp2_cid &cid, size_t cidlen,
|
int generate_encrypted_quic_connection_id(ngtcp2_cid &cid, size_t cidlen,
|
||||||
const uint8_t *cid_prefix,
|
const uint8_t *cid_prefix,
|
||||||
const uint8_t *key) {
|
const uint8_t *key) {
|
||||||
assert(cidlen > SHRPX_QUIC_CID_PREFIXLEN);
|
assert(cidlen == SHRPX_QUIC_SCIDLEN);
|
||||||
|
|
||||||
auto p = std::copy_n(cid_prefix, SHRPX_QUIC_CID_PREFIXLEN, cid.data);
|
if (RAND_bytes(cid.data, cidlen) != 1) {
|
||||||
|
|
||||||
if (RAND_bytes(p, cidlen - SHRPX_QUIC_CID_PREFIXLEN) != 1) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cid.datalen = cidlen;
|
cid.datalen = cidlen;
|
||||||
|
|
||||||
return encrypt_quic_connection_id(cid.data, cid.data, key);
|
auto p = cid.data + SHRPX_QUIC_CID_PREFIX_OFFSET;
|
||||||
|
|
||||||
|
std::copy_n(cid_prefix, SHRPX_QUIC_CID_PREFIXLEN, p);
|
||||||
|
|
||||||
|
return encrypt_quic_connection_id(p, p, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
int encrypt_quic_connection_id(uint8_t *dest, const uint8_t *src,
|
int encrypt_quic_connection_id(uint8_t *dest, const uint8_t *src,
|
||||||
|
|
|
@ -62,7 +62,10 @@ namespace shrpx {
|
||||||
struct UpstreamAddr;
|
struct UpstreamAddr;
|
||||||
|
|
||||||
constexpr size_t SHRPX_QUIC_SCIDLEN = 20;
|
constexpr size_t SHRPX_QUIC_SCIDLEN = 20;
|
||||||
|
constexpr size_t SHRPX_QUIC_SERVER_IDLEN = 2;
|
||||||
|
// SHRPX_QUIC_CID_PREFIXLEN includes SHRPX_QUIC_SERVER_IDLEN.
|
||||||
constexpr size_t SHRPX_QUIC_CID_PREFIXLEN = 8;
|
constexpr size_t SHRPX_QUIC_CID_PREFIXLEN = 8;
|
||||||
|
constexpr size_t SHRPX_QUIC_CID_PREFIX_OFFSET = 1;
|
||||||
constexpr size_t SHRPX_QUIC_DECRYPTED_DCIDLEN = 16;
|
constexpr size_t SHRPX_QUIC_DECRYPTED_DCIDLEN = 16;
|
||||||
constexpr size_t SHRPX_QUIC_CID_ENCRYPTION_KEYLEN = 16;
|
constexpr size_t SHRPX_QUIC_CID_ENCRYPTION_KEYLEN = 16;
|
||||||
constexpr size_t SHRPX_QUIC_MAX_UDP_PAYLOAD_SIZE = 1472;
|
constexpr size_t SHRPX_QUIC_MAX_UDP_PAYLOAD_SIZE = 1472;
|
||||||
|
@ -78,7 +81,9 @@ int quic_send_packet(const UpstreamAddr *faddr, const sockaddr *remote_sa,
|
||||||
size_t local_salen, const uint8_t *data, size_t datalen,
|
size_t local_salen, const uint8_t *data, size_t datalen,
|
||||||
size_t gso_size);
|
size_t gso_size);
|
||||||
|
|
||||||
int generate_quic_connection_id(ngtcp2_cid &cid, size_t cidlen);
|
int generate_quic_retry_connection_id(ngtcp2_cid &cid, size_t cidlen,
|
||||||
|
const uint8_t *server_id,
|
||||||
|
const uint8_t *key);
|
||||||
|
|
||||||
int generate_encrypted_quic_connection_id(ngtcp2_cid &cid, size_t cidlen,
|
int generate_encrypted_quic_connection_id(ngtcp2_cid &cid, size_t cidlen,
|
||||||
const uint8_t *cid_prefix,
|
const uint8_t *cid_prefix,
|
||||||
|
|
|
@ -128,7 +128,7 @@ int QUICConnectionHandler::handle_packet(const UpstreamAddr *faddr,
|
||||||
|
|
||||||
if (dcidlen == SHRPX_QUIC_SCIDLEN) {
|
if (dcidlen == SHRPX_QUIC_SCIDLEN) {
|
||||||
if (decrypt_quic_connection_id(
|
if (decrypt_quic_connection_id(
|
||||||
decrypted_dcid.data(), dcid,
|
decrypted_dcid.data(), dcid + SHRPX_QUIC_CID_PREFIX_OFFSET,
|
||||||
quicconf.upstream.cid_encryption_key.data()) != 0) {
|
quicconf.upstream.cid_encryption_key.data()) != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -419,9 +419,14 @@ int QUICConnectionHandler::send_retry(
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto config = get_config();
|
||||||
|
auto &quicconf = config->quic;
|
||||||
|
|
||||||
ngtcp2_cid retry_scid;
|
ngtcp2_cid retry_scid;
|
||||||
|
|
||||||
if (generate_quic_connection_id(retry_scid, SHRPX_QUIC_SCIDLEN) != 0) {
|
if (generate_quic_retry_connection_id(
|
||||||
|
retry_scid, SHRPX_QUIC_SCIDLEN, quicconf.upstream.server_id.data(),
|
||||||
|
quicconf.upstream.cid_encryption_key.data()) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1273,8 +1273,10 @@ void downstream_failure(DownstreamAddr *addr, const Address *raddr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_HTTP3
|
#ifdef ENABLE_HTTP3
|
||||||
int create_cid_prefix(uint8_t *cid_prefix) {
|
int create_cid_prefix(uint8_t *cid_prefix, const uint8_t *server_id) {
|
||||||
if (RAND_bytes(cid_prefix, SHRPX_QUIC_CID_PREFIXLEN) != 1) {
|
auto p = std::copy_n(server_id, SHRPX_QUIC_SERVER_IDLEN, cid_prefix);
|
||||||
|
|
||||||
|
if (RAND_bytes(p, SHRPX_QUIC_CID_PREFIXLEN - SHRPX_QUIC_SERVER_IDLEN) != 1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -467,8 +467,8 @@ void downstream_failure(DownstreamAddr *addr, const Address *raddr);
|
||||||
#ifdef ENABLE_HTTP3
|
#ifdef ENABLE_HTTP3
|
||||||
// Creates unpredictable SHRPX_QUIC_CID_PREFIXLEN bytes sequence which
|
// Creates unpredictable SHRPX_QUIC_CID_PREFIXLEN bytes sequence which
|
||||||
// is used as a prefix of QUIC Connection ID. This function returns
|
// is used as a prefix of QUIC Connection ID. This function returns
|
||||||
// -1 on failure.
|
// -1 on failure. |server_id| must be 2 bytes long.
|
||||||
int create_cid_prefix(uint8_t *cid_prefix);
|
int create_cid_prefix(uint8_t *cid_prefix, const uint8_t *server_id);
|
||||||
#endif // ENABLE_HTTP3
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
Loading…
Reference in New Issue