diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ec85ab99..58b4a6a26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ # Copyright (c) 2022, Alibaba Group Holding Limited -cmake_minimum_required (VERSION 2.6) +cmake_minimum_required (VERSION 3.5) project (xquic) set (xquic_VERSION_MAJOR 0) @@ -19,6 +19,7 @@ option (XQC_ENABLE_FEC "enable fec" OFF) option (XQC_ENABLE_XOR "enable fec scheme xor" OFF) option (XQC_ENABLE_RSC "enable fec scheme reed-solomon code" OFF) option (XQC_ENABLE_PKM "enable fec scheme packet mask" OFF) +option (XQC_PING_ATTACK_PROTECT "enable ping attack protection" OFF) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 54cc0ab3d..ab4b57716 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -1,6 +1,6 @@ # Copyright (c) 2022, Alibaba Group Holding Limited -cmake_minimum_required (VERSION 2.6) +cmake_minimum_required (VERSION 3.5) project (xquic) set (xquic_VERSION_MAJOR 0) diff --git a/demo/demo_client.c b/demo/demo_client.c index 9616fb704..2a28e23c2 100644 --- a/demo/demo_client.c +++ b/demo/demo_client.c @@ -207,6 +207,12 @@ typedef struct xqc_demo_cli_quic_config_s { int recreate_path; int close_path_id; + int use_x25519; + + xqc_msec_t path0_rebind_time; + xqc_msec_t path1_rebind_time; + uint8_t read_old_sockets; + } xqc_demo_cli_quic_config_t; @@ -1378,16 +1384,22 @@ xqc_demo_cli_socket_read_handler(xqc_demo_cli_user_conn_t *user_conn, int fd) { user_path = &user_conn->paths[i]; } + + if (user_conn->paths[i].is_active + && user_conn->paths[i].rebind_fd == fd) + { + user_path = &user_conn->paths[i]; + } + } if (user_path == NULL) { return; } - // printf("socket read: path%"PRIu64" fd:%d\n", user_path->path_id, user_path->fd); do { - recv_size = recvfrom(user_path->fd, packet_buf, sizeof(packet_buf), 0, + recv_size = recvfrom(fd, packet_buf, sizeof(packet_buf), 0, (struct sockaddr *)&addr, &addr_len); if (recv_size < 0 && get_sys_errno() == EAGAIN) { break; @@ -1398,7 +1410,7 @@ xqc_demo_cli_socket_read_handler(xqc_demo_cli_user_conn_t *user_conn, int fd) } user_path->local_addrlen = sizeof(struct sockaddr_in6); - xqc_int_t ret = getsockname(user_path->fd, (struct sockaddr*)&user_path->local_addr, + xqc_int_t ret = getsockname(fd, (struct sockaddr*)&user_path->local_addr, &user_path->local_addrlen); if (ret != 0) { printf("getsockname error, errno: %d\n", get_sys_errno()); @@ -1578,11 +1590,13 @@ xqc_demo_cli_rebind_path0(int fd, short what, void *arg) // change fd int temp = user_conn->paths[0].fd; user_conn->paths[0].fd = user_conn->paths[0].rebind_fd; - user_conn->paths[0].rebind_fd = user_conn->paths[0].fd; + user_conn->paths[0].rebind_fd = temp; //stop read from the old socket - event_del(user_conn->paths[0].ev_socket); - user_conn->paths[0].ev_socket = NULL; + if (!user_conn->ctx->args->quic_cfg.read_old_sockets) { + event_del(user_conn->paths[0].ev_socket); + user_conn->paths[0].ev_socket = NULL; + } xqc_h3_conn_send_ping(user_conn->ctx->engine, &user_conn->cid, NULL); } @@ -1596,10 +1610,12 @@ xqc_demo_cli_rebind_path1(int fd, short what, void *arg) // change fd int temp = user_conn->paths[1].fd; user_conn->paths[1].fd = user_conn->paths[1].rebind_fd; - user_conn->paths[1].rebind_fd = user_conn->paths[1].fd; + user_conn->paths[1].rebind_fd = temp; - event_del(user_conn->paths[1].ev_socket); - user_conn->paths[1].ev_socket = NULL; + if (!user_conn->ctx->args->quic_cfg.read_old_sockets) { + event_del(user_conn->paths[1].ev_socket); + user_conn->paths[1].ev_socket = NULL; + } xqc_h3_conn_send_ping(user_conn->ctx->engine, &user_conn->cid, NULL); } @@ -1661,6 +1677,10 @@ xqc_demo_cli_init_conn_ssl_config(xqc_conn_ssl_config_t *conn_ssl_config, conn_ssl_config->transport_parameter_data = args->quic_cfg.tp; conn_ssl_config->transport_parameter_data_len = args->quic_cfg.tp_len; } + + if (args->quic_cfg.use_x25519) { + conn_ssl_config->tls_groups = XQC_TLS_GROUP_X25519_FIRST; + } } void @@ -1765,6 +1785,7 @@ xqc_demo_cli_init_args(xqc_demo_cli_client_args_t *args) args->quic_cfg.close_path_id = 1; args->quic_cfg.backup_path_id = 1; args->quic_cfg.quic_version = XQC_VERSION_V1; + args->quic_cfg.use_x25519 = 0; args->req_cfg.throttled_req = -1; @@ -1919,8 +1940,9 @@ xqc_demo_cli_usage(int argc, char *argv[]) " -B Set initial path standby after recvd first application data, and set initial path available after X ms\n" " -I Idle interval between requests (ms)\n" " -n Throttling the {1,2,...}xn-th requests\n" - " -e NAT rebinding on path 0\n" - " -E NAT rebinding on path 1\n" + " -e NAT rebinding on path 0 after x ms\n" + " -E NAT rebinding on path 1 after x ms\n" + " -O Also read packets from old sockets after rebinding\n" " -F MTU size (default: 1200)\n" " -G Google connection options (e.g. CBBR,TBBR)\n" " -x Extend the number of requests to X\n" @@ -1928,6 +1950,7 @@ xqc_demo_cli_usage(int argc, char *argv[]) " -y cid rotation after x ms\n" " -Y cid retirement after x ms\n" " -f max path id\n" + " -5 use X25519 group as the first choice\n" , prog); } @@ -1935,7 +1958,7 @@ void xqc_demo_cli_parse_args(int argc, char *argv[], xqc_demo_cli_client_args_t *args) { int ch = 0; - while ((ch = getopt(argc, argv, "a:p:c:Ct:S:0m:A:D:l:L:k:K:U:u:dMoi:w:Ps:b:Z:NQT:R:V:B:I:n:eEF:G:r:x:y:Y:f:z:q6")) != -1) { + while ((ch = getopt(argc, argv, "a:p:c:Ct:S:0m:A:D:l:L:k:K:U:u:dMoi:w:Ps:b:Z:NQT:R:V:B:I:n:e:E:F:G:r:x:y:Y:f:z:q65O")) != -1) { switch (ch) { /* server ip */ case '6': @@ -2184,12 +2207,19 @@ xqc_demo_cli_parse_args(int argc, char *argv[], xqc_demo_cli_client_args_t *args case 'e': printf("option rebinding path0 after 2s\n"); args->net_cfg.rebind_p0 = 1; + args->quic_cfg.path0_rebind_time = atoi(optarg); break; case 'E': printf("option rebinding path1 after 3s\n"); args->net_cfg.rebind_p1 = 1; - break; + args->quic_cfg.path1_rebind_time = atoi(optarg); + break; + + case 'O': + printf("also read from old sockets after rebinding\n"); + args->quic_cfg.read_old_sockets = 1; + break; case 'F': printf("MTU size: %s\n", optarg); @@ -2216,6 +2246,11 @@ xqc_demo_cli_parse_args(int argc, char *argv[], xqc_demo_cli_client_args_t *args args->quic_cfg.init_max_path_id = atoi(optarg); break; + case '5': + printf("use x25519\n"); + args->quic_cfg.use_x25519 = 1; + break; + default: printf("other option :%c\n", ch); xqc_demo_cli_usage(argc, argv); @@ -2730,8 +2765,8 @@ xqc_demo_cli_start(xqc_demo_cli_user_conn_t *user_conn, xqc_demo_cli_client_args xqc_demo_cli_rebind_path0, user_conn); struct timeval tv = { - .tv_sec = 2, - .tv_usec = 0, + .tv_sec = args->quic_cfg.path0_rebind_time / 1000, + .tv_usec = (args->quic_cfg.path0_rebind_time % 1000) * 1000, }; event_add(user_conn->ev_rebinding_p0, &tv); } @@ -2741,8 +2776,8 @@ xqc_demo_cli_start(xqc_demo_cli_user_conn_t *user_conn, xqc_demo_cli_client_args xqc_demo_cli_rebind_path1, user_conn); struct timeval tv = { - .tv_sec = 3, - .tv_usec = 0, + .tv_sec = args->quic_cfg.path1_rebind_time / 1000, + .tv_usec = (args->quic_cfg.path1_rebind_time % 1000) * 1000, }; event_add(user_conn->ev_rebinding_p1, &tv); } diff --git a/include/xquic/xquic.h b/include/xquic/xquic.h index 636362c2f..dd80dbff3 100644 --- a/include/xquic/xquic.h +++ b/include/xquic/xquic.h @@ -72,7 +72,9 @@ typedef enum xqc_proto_version_s { #define XQC_RESET_TOKEN_MAX_KEY_LEN 256 - +#define XQC_TOKEN_MAX_KEY_VERSION 4 +#define XQC_TOKEN_VERSION_MASK 3 +#define XQC_TOKEN_MAX_KEY_LEN 256 /** * the max message count of iovec in sendmmsg */ @@ -417,6 +419,17 @@ typedef void (*xqc_conn_ready_to_create_path_notify_pt)(const xqc_cid_t *scid, typedef xqc_int_t (*xqc_conn_cert_cb_pt)(const char *sni, void **chain, void **crt, void **key, void *user_data); +typedef void (*xqc_conn_ssl_msg_cb_pt)(int msg_type, + const void *msg, size_t msg_len, void *user_data); + +/** + * @brief to determine whether to send a retry packet + * @return XQC_TRUE(1): meet condition to send a retry packet + * XQC_FALSE(0): don't meet condition to send a retry packet or an error occurred while judging the condition + */ +typedef int (*xqc_conn_retry_packet_pt)(xqc_engine_t *engine, xqc_connection_t *conn, + const xqc_cid_t *cid, void *user_data); + /** * @brief multi-path create callback function * @@ -703,6 +716,17 @@ typedef struct xqc_transport_callbacks_s { */ xqc_conn_cert_cb_pt conn_cert_cb; + xqc_conn_ssl_msg_cb_pt conn_ssl_msg_cb; + /** + * @brief check the conditions to send retry packet + */ + xqc_conn_retry_packet_pt conn_retry_packet_condition_check; + /** + * @brief server send packet before server accept the connection. + * for example, retry packet is sent when the application layer connection has not been established, + */ + xqc_socket_write_pt conn_send_packet_before_accept; + } xqc_transport_callbacks_t; @@ -1165,6 +1189,11 @@ typedef struct xqc_config_s { /** for warning when the number of elements in one bucket exceeds the value of hash_conflict_threshold*/ uint32_t hash_conflict_threshold; + + /* used to encrypt token */ + unsigned char token_key_list[XQC_TOKEN_MAX_KEY_VERSION][XQC_TOKEN_MAX_KEY_LEN]; + uint16_t tk_len_list[XQC_TOKEN_MAX_KEY_VERSION]; + uint8_t cur_tk_index; /* current used token key version */ } xqc_config_t; @@ -1261,6 +1290,11 @@ typedef struct xqc_conn_ssl_config_s { * certificate verify flag. which is a bit-map flag defined in xqc_cert_verify_flag_e */ uint8_t cert_verify_flag; + + /** + * ssl curve list (groups). If not set, xquic will use the default engine-level value. + */ + xqc_tls_group_type_t tls_groups; } xqc_conn_ssl_config_t; typedef struct xqc_linger_s { @@ -1490,6 +1524,13 @@ typedef struct xqc_conn_settings_s { uint64_t receive_timestamps_exponent; uint8_t disable_pn_skipping; + + /* The client can specify its own scid or dcid. Default: 0 */ + uint8_t specify_client_scid; + uint8_t client_scid[XQC_MAX_CID_LEN]; + uint8_t specify_client_dcid; + uint8_t client_dcid[XQC_MAX_CID_LEN]; + } xqc_conn_settings_t; diff --git a/include/xquic/xquic_typedef.h b/include/xquic/xquic_typedef.h index fc1a46d18..604c2a7b7 100644 --- a/include/xquic/xquic_typedef.h +++ b/include/xquic/xquic_typedef.h @@ -229,6 +229,7 @@ typedef struct xqc_http_priority_s { uint8_t schedule; uint8_t reinject; uint32_t fec; + uint8_t fastpath; } xqc_h3_priority_t; /* ALPN definition */ @@ -333,4 +334,17 @@ typedef enum { XQC_APP_PATH_STATUS_MAX, } xqc_app_path_status_t; +typedef enum xqc_tls_msg_type_e { + XQC_TLS_1_3_CLIENT_HELLO, + XQC_TLS_1_3_SERVER_HELLO +} xqc_tls_msg_type_t; + +typedef enum xqc_tls_group_type_e { + XQC_TLS_GROUP_DEFAULT = 0, + XQC_TLS_GROUP_P256_FIRST = 1, + XQC_TLS_GROUP_X25519_FIRST = 2, + XQC_TLS_GROUP_P384_FIRST = 3, + XQC_TLS_GROUP_P521_FIRST = 4, +} xqc_tls_group_type_t; + #endif /*_XQUIC_TYPEDEF_H_INCLUDED_*/ diff --git a/scripts/case_test.sh b/scripts/case_test.sh index ab217ade6..fd6b692c0 100755 --- a/scripts/case_test.sh +++ b/scripts/case_test.sh @@ -57,7 +57,8 @@ fi echo -e "server refuse ...\c" -${CLIENT_BIN} -x 46 -t 10 >> stdlog +${CLIENT_BIN} -x 46 -t 1 >> stdlog +sleep 10 result=`grep "conn close notified by refuse" slog` if [ -n "$result" ]; then echo ">>>>>>>> pass:1" @@ -756,6 +757,29 @@ else fi rm -f test_session +clear_log +echo -e "retry packet send ...\c" +killall test_server +rm -f xqc_token +${SERVER_BIN} -l d -e -x 601 > /dev/null & +sleep 1 +result=`${CLIENT_BIN} -s 1024 -l d -t 1 -E --conn_options CBBR|grep ">>>>>>>> pass"` +errlog=`grep_err_log` +slog_res=`grep -E "<==.*xqc_conn_send_retry ok" slog` +clog_res=`grep -E "packet_parse_retry" clog` +#echo "$result" +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ -n "$slog_res" ] && [ -n "$clog_res" ]; then + echo ">>>>>>>> pass:1" + case_print_result "retry_packet_send" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "retry_packet_send" "fail" + echo "$errlog" + echo "$slog_res" + echo "$clog_res" +fi + + clear_log echo -e "server cid negotiate ...\c" @@ -860,7 +884,6 @@ else echo "$errlog" fi - clear_log echo -e "send 1K data ...\c" result=`${CLIENT_BIN} -s 1024 -l d -t 1 -E --conn_options CBBR|grep ">>>>>>>> pass"` @@ -4922,4 +4945,4 @@ else case_print_result "ack_timestamp_frame_case_6" "fail" fi -cd - \ No newline at end of file +cd - diff --git a/scripts/xquic.lds b/scripts/xquic.lds index 529413d9d..9335a3fb5 100644 --- a/scripts/xquic.lds +++ b/scripts/xquic.lds @@ -128,6 +128,7 @@ XQUIC_VERS_1.0 { xqc_reed_solomon_code_cb; xqc_xor_code_cb; xqc_packet_mask_code_cb; + xqc_conn_set_init_idle_timeout; local: *; }; diff --git a/src/common/xqc_random.c b/src/common/xqc_random.c index a35741e22..f4c48ea8d 100644 --- a/src/common/xqc_random.c +++ b/src/common/xqc_random.c @@ -23,15 +23,19 @@ long xqc_random(void) { #ifdef XQC_SYS_WINDOWS - unsigned int val; - if (rand_s(&val)) { + unsigned int val = 0; + long result = 0; + + if (rand_s(&val) == 0) { val = rand(); } - return (long)val & 0xFFFFFFFF; + + result = (long)(val & 0x7FFFFFFF); + return result; #else - return random(); + long result = random(); + return result; #endif - } xqc_random_generator_t * diff --git a/src/common/xqc_time.c b/src/common/xqc_time.c index be210a77a..6b7404425 100644 --- a/src/common/xqc_time.c +++ b/src/common/xqc_time.c @@ -52,5 +52,11 @@ xqc_now() return ul; } +xqc_usec_t +xqc_update_avg_time(xqc_usec_t new_time, xqc_usec_t ori_time, xqc_int_t ori_time_num) +{ + return (xqc_usec_t)(1.0 * new_time / (ori_time_num + 1) + 1.0 * ori_time / (ori_time_num + 1) * ori_time_num); +} + xqc_timestamp_pt xqc_realtime_timestamp = xqc_now; xqc_timestamp_pt xqc_monotonic_timestamp = xqc_now; diff --git a/src/common/xqc_time.h b/src/common/xqc_time.h index dfbc756fa..8c07513b1 100644 --- a/src/common/xqc_time.h +++ b/src/common/xqc_time.h @@ -30,5 +30,7 @@ extern xqc_timestamp_pt xqc_realtime_timestamp; */ extern xqc_timestamp_pt xqc_monotonic_timestamp; +xqc_usec_t xqc_update_avg_time(xqc_usec_t new_time, xqc_usec_t ori_time, xqc_int_t ori_time_num); + #endif /* _XQC_TIME_H_INCLUDED_ */ diff --git a/src/congestion_control/xqc_bbr.c b/src/congestion_control/xqc_bbr.c index 6392c7520..d82aa8175 100644 --- a/src/congestion_control/xqc_bbr.c +++ b/src/congestion_control/xqc_bbr.c @@ -581,7 +581,7 @@ xqc_bbr_enter_probe_bw(xqc_bbr_t *bbr, xqc_sample_t *sampler) { bbr->mode = BBR_PROBE_BW; bbr->cwnd_gain = xqc_bbr_cwnd_gain; - bbr->cycle_idx = xqc_random() % (XQC_BBR_CYCLE_LENGTH - 1); + bbr->cycle_idx = (uint32_t)(xqc_random() % (XQC_BBR_CYCLE_LENGTH - 1)); bbr->cycle_idx = bbr->cycle_idx == 0 ? bbr->cycle_idx : bbr->cycle_idx + 1; bbr->pacing_gain = xqc_bbr_get_pacing_gain(bbr, bbr->cycle_idx); bbr->cycle_start_stamp = sampler->now; diff --git a/src/http3/xqc_h3_request.c b/src/http3/xqc_h3_request.c index 1c820f620..7ee743152 100644 --- a/src/http3/xqc_h3_request.c +++ b/src/http3/xqc_h3_request.c @@ -72,7 +72,7 @@ xqc_h3_request_destroy(xqc_h3_request_t *h3_request) "pacing_blk:%ud|pacing_blk_time:%ui|begin_state:%s|end_state:%s|" "is_fec_protected:%ud|fec_reco_pkt_cnt:%ud|fec_block_size_mode:%ud|" "fst_rpr_ts:%ui|last_rpr_ts:%ui|fec_fin_delay:%ui|" - "external_stream_info:%s|", + "external_stream_info:%s|fastpath:%ud|", h3s->stream_id, stats.stream_close_msg ? stats.stream_close_msg : "", stats.stream_err, stats.recv_body_size, stats.send_body_size, stats.recv_header_size, stats.send_header_size, @@ -104,7 +104,8 @@ xqc_h3_request_destroy(xqc_h3_request_t *h3_request) stats.is_fec_protected, stats.fec_recov_cnt, h3_request->block_size_mode, stats.fst_rpr_time, stats.last_rpr_time, stats.fec_req_delay_time, - stats.extern_stream_info + stats.extern_stream_info, + h3s->priority.fastpath ); if (h3_request->request_if->h3_request_close_notify) { @@ -1018,6 +1019,9 @@ xqc_h3_request_closing(xqc_h3_request_t *h3r, xqc_int_t err) #define XQC_PRIORITY_FEC_LEN 4 #define XQC_PRIORITY_FEC_VAL_LEN 8 +#define XQC_PRIORITY_FASTPATH ", p" +#define XQC_PRIORITY_FASTPATH_LEN 3 + void xqc_h3_priority_init(xqc_h3_priority_t *prio) { @@ -1026,6 +1030,7 @@ xqc_h3_priority_init(xqc_h3_priority_t *prio) prio->schedule = 0; prio->reinject = 0; prio->fec = XQC_DEFAULT_SIZE_REQ; + prio->fastpath = 0; } size_t @@ -1039,7 +1044,8 @@ xqc_write_http_priority(xqc_h3_priority_t *prio, + XQC_PRIORITY_INCREMENTAL_LEN + XQC_PRIORITY_SCHEDULE_LEN + 1 + XQC_PRIORITY_REINJECT_LEN + 1 - + XQC_PRIORITY_FEC_LEN + XQC_PRIORITY_FEC_VAL_LEN; + + XQC_PRIORITY_FEC_LEN + XQC_PRIORITY_FEC_VAL_LEN + + XQC_PRIORITY_FASTPATH_LEN; if (need > dstcap) { return -XQC_H3_BUFFER_EXCEED; } @@ -1069,6 +1075,11 @@ xqc_write_http_priority(xqc_h3_priority_t *prio, xqc_free(fec_str); + if (prio->fastpath) { + xqc_memcpy(dst, XQC_PRIORITY_FASTPATH, XQC_PRIORITY_FASTPATH_LEN); + dst += XQC_PRIORITY_FASTPATH_LEN; + } + return dst - begin; } @@ -1127,6 +1138,9 @@ xqc_parse_http_priority(xqc_h3_priority_t *dst, goto end; } prio.fec = strtoul(p, NULL, XQC_DECIMAL); + } else if (strncmp(p, "p", xqc_lengthof("p")) == 0) { + p += xqc_lengthof("p"); + prio.fastpath = 1; } p = strchr(p, ','); diff --git a/src/http3/xqc_h3_stream.c b/src/http3/xqc_h3_stream.c index 3c84c928a..b12fad451 100644 --- a/src/http3/xqc_h3_stream.c +++ b/src/http3/xqc_h3_stream.c @@ -2117,12 +2117,16 @@ xqc_h3_stream_set_priority(xqc_h3_stream_t *h3s, xqc_h3_priority_t *prio) h3s->priority.schedule = prio->schedule; h3s->priority.reinject = prio->reinject; h3s->priority.fec = prio->fec; + h3s->priority.fastpath = prio->fastpath; if (h3s->stream == NULL) { xqc_log(h3s->log, XQC_LOG_ERROR, "|transport stream was NULL|stream_id:%ui|", h3s->stream_id); return; } + if (h3s->priority.fastpath) { + xqc_stream_set_priority(h3s->stream, XQC_STREAM_PRI_HIGH); + } xqc_stream_set_multipath_usage(h3s->stream, h3s->priority.schedule, h3s->priority.reinject); h3s->stream->stream_fec_blk_mode = xqc_set_stream_fec_block_mode(h3s->priority.fec); h3s->h3r->block_size_mode = h3s->stream->stream_fec_blk_mode; diff --git a/src/tls/xqc_ssl_cbs.h b/src/tls/xqc_ssl_cbs.h index 3d6dc2173..1b2429f05 100644 --- a/src/tls/xqc_ssl_cbs.h +++ b/src/tls/xqc_ssl_cbs.h @@ -18,6 +18,14 @@ */ void xqc_ssl_keylog_cb(const SSL *ssl, const char *line); +/** + * @brief log tls message + * @see SSL_CTX_set_msg_callback + */ +void +xqc_ssl_msg_cb(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg); + /** * @brief select an ALPN protocol from the client's list of offered protocols diff --git a/src/tls/xqc_tls.c b/src/tls/xqc_tls.c index 66c3256ca..9d78c0f1c 100644 --- a/src/tls/xqc_tls.c +++ b/src/tls/xqc_tls.c @@ -198,6 +198,17 @@ xqc_tls_init_client_ssl(xqc_tls_t *tls, xqc_tls_config_t *cfg) SSL_set_tlsext_host_name(ssl, hostname); + if (cfg->tls_groups != NULL) { + /* override the default engine-level value with the connection-level value */ + ret = SSL_set1_curves_list(ssl, cfg->tls_groups); + if (ret != XQC_SSL_SUCCESS) { + xqc_log(tls->log, XQC_LOG_ERROR, "|set curves list error|%s|", + ERR_error_string(ERR_get_error(), NULL)); + ret = -XQC_TLS_INTERNAL; + goto end; + } + } + /* * set alpn in ClientHello. for client, xquic set alpn for every ssl instance. while server set * the alpn select callback function while initializing tls context. @@ -603,13 +614,7 @@ xqc_int_t xqc_tls_encrypt_header(xqc_tls_t *tls, xqc_encrypt_level_t level, xqc_pkt_type_t pkt_type, uint8_t *header, uint8_t *pktno, uint8_t *end) { - xqc_crypto_t *crypto = tls->crypto[level]; - if (crypto == NULL) { - xqc_log(tls->log, XQC_LOG_ERROR, "|crypto not initialized|level:%d|", level); - return -XQC_TLS_INVALID_STATE; - } - - return xqc_crypto_encrypt_header(crypto, pkt_type, header, pktno, end); + return xqc_crypto_encrypt_header(tls->crypto[level], pkt_type, header, pktno, end); } @@ -619,12 +624,6 @@ xqc_tls_encrypt_payload(xqc_tls_t *tls, xqc_encrypt_level_t level, uint8_t *header, size_t header_len, uint8_t *payload, size_t payload_len, uint8_t *dst, size_t dst_cap, size_t *dst_len) { - xqc_crypto_t *crypto = tls->crypto[level]; - if (crypto == NULL) { - xqc_log(tls->log, XQC_LOG_ERROR, "|crypto not initialized|level:%d|", level); - return -XQC_TLS_INVALID_STATE; - } - xqc_uint_t key_phase = 0; if (level == XQC_ENC_LEV_1RTT) { key_phase = XQC_PACKET_SHORT_HEADER_KEY_PHASE(header); @@ -634,7 +633,7 @@ xqc_tls_encrypt_payload(xqc_tls_t *tls, xqc_encrypt_level_t level, } } - return xqc_crypto_encrypt_payload(crypto, pktno, key_phase, path_id, + return xqc_crypto_encrypt_payload(tls->crypto[level], pktno, key_phase, path_id, header, header_len, payload, payload_len, dst, dst_cap, dst_len); } @@ -683,7 +682,7 @@ xqc_tls_decrypt_payload(xqc_tls_t *tls, xqc_encrypt_level_t level, xqc_bool_t xqc_tls_is_key_ready(xqc_tls_t *tls, xqc_encrypt_level_t level, xqc_key_type_t key_type) { - if (NULL == tls->crypto[level]) { + if (NULL == tls || NULL == tls->crypto[level]) { return XQC_FALSE; } @@ -792,26 +791,25 @@ xqc_tls_discard_old_1rtt_keys(xqc_tls_t *tls) } xqc_int_t -xqc_tls_cal_retry_integrity_tag(xqc_tls_t *tls, +xqc_tls_cal_retry_integrity_tag(xqc_log_t *log, uint8_t *retry_pseudo_packet, size_t retry_pseudo_packet_len, - uint8_t *dst, size_t dst_cap, size_t *dst_len) + uint8_t *dst, size_t dst_cap, size_t *dst_len, xqc_proto_version_t ver) { xqc_int_t ret = XQC_OK; - xqc_crypto_t *crypto = xqc_crypto_create(XQC_TLS13_AES_128_GCM_SHA256, tls->log); + xqc_crypto_t *crypto = xqc_crypto_create(XQC_TLS13_AES_128_GCM_SHA256, log); if (crypto == NULL) { - xqc_log(tls->log, XQC_LOG_ERROR, "|create retry crypto error|"); + xqc_log(log, XQC_LOG_ERROR, "|create retry crypto error|"); return -XQC_TLS_NOMEM; } - xqc_proto_version_t ver = tls->version; ret = xqc_crypto_aead_encrypt(crypto, "", 0, xqc_crypto_retry_key[ver], strlen(xqc_crypto_retry_key[ver]), xqc_crypto_retry_nonce[ver], strlen(xqc_crypto_retry_nonce[ver]), retry_pseudo_packet, retry_pseudo_packet_len, dst, dst_cap, dst_len); if (ret != XQC_OK) { - xqc_log(tls->log, XQC_LOG_ERROR, "|calculate retry integrity tag error|"); + xqc_log(log, XQC_LOG_ERROR, "|calculate retry integrity tag error|"); } xqc_crypto_destroy(crypto); @@ -834,6 +832,30 @@ xqc_ssl_keylog_cb(const SSL *ssl, const char *line) } } +void +xqc_ssl_msg_cb(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg) +{ + xqc_tls_t *tls = (xqc_tls_t *)SSL_get_app_data(ssl); + if (content_type == SSL3_RT_HANDSHAKE) { + const unsigned char *p = buf; + if (*p == SSL3_MT_CLIENT_HELLO && !write_p) { + // Incoming ClientHello + if (tls->cbs->msg_cb) { + tls->cbs->msg_cb(XQC_TLS_1_3_CLIENT_HELLO, + buf, len, tls->user_data); + } + + } else if (*p == SSL3_MT_SERVER_HELLO && write_p) { + // Outgoing ServerHello + if (tls->cbs->msg_cb) { + tls->cbs->msg_cb(XQC_TLS_1_3_SERVER_HELLO, + buf, len, tls->user_data); + } + } + } +} + int xqc_ssl_alpn_select_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, diff --git a/src/tls/xqc_tls.h b/src/tls/xqc_tls.h index 71364b96e..3ddf2c8ca 100644 --- a/src/tls/xqc_tls.h +++ b/src/tls/xqc_tls.h @@ -27,7 +27,6 @@ #undef X509_NAME #endif - /** * @brief init tls context. MUST be called before any creation of xqc_tls_t */ @@ -209,9 +208,9 @@ void xqc_tls_discard_old_1rtt_keys(xqc_tls_t *tls); /** * @brief encrypt retry pseudo-packet to calculate retry integrity tag */ -xqc_int_t xqc_tls_cal_retry_integrity_tag(xqc_tls_t *tls, +xqc_int_t xqc_tls_cal_retry_integrity_tag(xqc_log_t *log, uint8_t *retry_pseudo_packet, size_t retry_pseudo_packet_len, - uint8_t *dst, size_t dst_cap, size_t *dst_len); + uint8_t *dst, size_t dst_cap, size_t *dst_len, xqc_proto_version_t ver); void xqc_tls_get_selected_alpn(xqc_tls_t *tls, const char **out_alpn, size_t *out_len); diff --git a/src/tls/xqc_tls_ctx.c b/src/tls/xqc_tls_ctx.c index f857c9bf1..fd6723fec 100644 --- a/src/tls/xqc_tls_ctx.c +++ b/src/tls/xqc_tls_ctx.c @@ -342,6 +342,10 @@ xqc_tls_ctx_create(xqc_tls_type_t type, const xqc_engine_ssl_config_t *cfg, SSL_CTX_set_keylog_callback(ctx->ssl_ctx, xqc_ssl_keylog_cb); } + if (cbs->msg_cb) { + SSL_CTX_set_msg_callback(ctx->ssl_ctx, xqc_ssl_msg_cb); + } + return ctx; fail: diff --git a/src/tls/xqc_tls_defs.h b/src/tls/xqc_tls_defs.h index 9fbacb4e3..5ed1013b9 100644 --- a/src/tls/xqc_tls_defs.h +++ b/src/tls/xqc_tls_defs.h @@ -87,6 +87,8 @@ typedef struct xqc_tls_config_s { uint8_t *trans_params; size_t trans_params_len; + char *tls_groups; + } xqc_tls_config_t; @@ -138,6 +140,10 @@ typedef void (*xqc_tls_handshake_completed_pt)(void *user_data); typedef xqc_int_t (*xqc_tls_cert_cb_pt)(const char *sni, void **chain, void **crt, void **key, void *user_data); + +typedef void (*xqc_tls_msg_cb_pt)(int msg_type, + const void *msg, size_t msg_len, void *user_data); + /** * @brief definition of callback functions to upper layer */ @@ -169,6 +175,8 @@ typedef struct xqc_tls_callbacks_s { xqc_tls_handshake_completed_pt hsk_completed_cb; xqc_tls_cert_cb_pt cert_cb; + + xqc_tls_msg_cb_pt msg_cb; } xqc_tls_callbacks_t; diff --git a/src/transport/xqc_client.c b/src/transport/xqc_client.c index 905249ed6..1f7b0a33c 100644 --- a/src/transport/xqc_client.c +++ b/src/transport/xqc_client.c @@ -16,6 +16,16 @@ #include "src/tls/xqc_tls.h" #include "src/transport/xqc_datagram.h" +#define XQC_TLS_GROUP_MAX 5 + +const char *xqc_tls_group_str[XQC_TLS_GROUP_MAX] = { + XQC_TLS_GROUPS, + "P-256:X25519:P-384:P-521", + "X25519:P-256:P-384:P-521", + "P-384:X25519:P-256:P-521", + "P-521:P-384:X25519:P-256", +}; + xqc_connection_t * xqc_client_connect(xqc_engine_t *engine, const xqc_conn_settings_t *conn_settings, const unsigned char *token, unsigned token_len, const char *server_host, int no_crypto_flag, @@ -24,6 +34,8 @@ xqc_client_connect(xqc_engine_t *engine, const xqc_conn_settings_t *conn_setting { xqc_cid_t dcid; xqc_cid_t scid; + xqc_cid_init_zero(&dcid); + xqc_cid_init_zero(&scid); if (NULL == conn_ssl_config) { xqc_log(engine->log, XQC_LOG_ERROR, @@ -37,12 +49,24 @@ xqc_client_connect(xqc_engine_t *engine, const xqc_conn_settings_t *conn_setting return NULL; } - if (xqc_generate_cid(engine, NULL, &scid, 0) != XQC_OK - || xqc_generate_cid(engine, NULL, &dcid, 0) != XQC_OK) - { - xqc_log(engine->log, XQC_LOG_ERROR, - "|generate dcid or scid error|"); - return NULL; + if (conn_settings->specify_client_scid == 1) { + scid.cid_len = xqc_engine_config_get_cid_len(engine); + xqc_memcpy(scid.cid_buf, conn_settings->client_scid, scid.cid_len); + } else { + if (xqc_generate_cid(engine, NULL, &scid, 0) != XQC_OK) { + xqc_log(engine->log, XQC_LOG_ERROR, "|generate scid error|"); + return NULL; + } + } + + if (conn_settings->specify_client_dcid == 1) { + dcid.cid_len = xqc_engine_config_get_cid_len(engine); + xqc_memcpy(dcid.cid_buf, conn_settings->client_dcid, dcid.cid_len); + } else { + if (xqc_generate_cid(engine, NULL, &dcid, 0) != XQC_OK) { + xqc_log(engine->log, XQC_LOG_ERROR, "|generate dcid error|"); + return NULL; + } } xqc_connection_t *xc = xqc_client_create_connection(engine, dcid, scid, conn_settings, @@ -133,10 +157,23 @@ xqc_client_create_tls(xqc_connection_t *conn, const xqc_conn_ssl_config_t *conn_ size_t alpn_cap; unsigned char *hostname_buf; size_t host_cap; + size_t tls_group_len; /* init tls config */ cfg.cert_verify_flag = conn_ssl_config->cert_verify_flag; cfg.no_crypto_flag = no_crypto_flag; + cfg.tls_groups = NULL; + + if (conn_ssl_config->tls_groups > 0 && conn_ssl_config->tls_groups < XQC_TLS_GROUP_MAX) { + tls_group_len = strlen(xqc_tls_group_str[conn_ssl_config->tls_groups]); + cfg.tls_groups = xqc_calloc(tls_group_len + 1, sizeof(char)); + if (NULL == cfg.tls_groups) { + xqc_log(conn->log, XQC_LOG_ERROR, "|malloc for tls groups fail|"); + ret = -XQC_EMALLOC; + goto end; + } + xqc_memcpy(cfg.tls_groups, xqc_tls_group_str[conn_ssl_config->tls_groups], tls_group_len); + } /* copy session ticket */ cfg.session_ticket = xqc_malloc(conn_ssl_config->session_ticket_len + 1); @@ -194,6 +231,10 @@ xqc_client_create_tls(xqc_connection_t *conn, const xqc_conn_ssl_config_t *conn_ } end: + if (cfg.tls_groups) { + xqc_free(cfg.tls_groups); + } + if (cfg.session_ticket) { xqc_free(cfg.session_ticket); } diff --git a/src/transport/xqc_conn.c b/src/transport/xqc_conn.c index 3bbec4b61..ed3e83565 100644 --- a/src/transport/xqc_conn.c +++ b/src/transport/xqc_conn.c @@ -32,8 +32,9 @@ #include "src/transport/xqc_fec.h" #include "src/transport/xqc_fec_scheme.h" #include "src/tls/xqc_tls.h" +#include "src/tls/xqc_tls_common.h" #include - +#include xqc_conn_settings_t internal_default_conn_settings = { .pacing_on = 0, @@ -112,10 +113,13 @@ xqc_conn_settings_t internal_default_conn_settings = { .control_pto_value = 0, .max_udp_payload_size = XQC_CONN_MAX_UDP_PAYLOAD_SIZE, - .extended_ack_features = 0, + .extended_ack_features = 0, .max_receive_timestamps_per_ack = 0, .receive_timestamps_exponent = 0, - .disable_pn_skipping = 0 + .disable_pn_skipping = 0, + + .specify_client_scid = 0, + .specify_client_dcid = 0 }; @@ -407,6 +411,9 @@ static const char * const xqc_conn_flag_to_str[XQC_CONN_FLAG_SHIFT_NUM] = { [XQC_CONN_FLAG_DGRAM_MSS_NOTIFY_SHIFT] = "DGRAM_MSS_NOTIFY", [XQC_CONN_FLAG_MP_WAIT_MP_READY_SHIFT] = "MP_WAIT_MP_READY", [XQC_CONN_FLAG_MP_READY_NOTIFY_SHIFT] = "MP_READY_NOTIFY", + [XQC_CONN_FLAG_HANDSHAKE_DONE_SENT_SHIFT] = "HANDSHAKE_DONE_SENT", + [XQC_CONN_FLAG_SERVER_ACCEPT_SHIFT] = "SERVER_ACCEPT", + [XQC_CONN_FLAG_RETRY_SENT_SHIFT] = "RETRY_PACKET_SENT", }; @@ -1183,11 +1190,6 @@ xqc_conn_server_create(xqc_engine_t *engine, const struct sockaddr *local_addr, goto fail; } - ret = xqc_conn_create_server_tls(conn); - if (ret != XQC_OK) { - goto fail; - } - ret = xqc_conn_server_init_path_addr(conn, XQC_INITIAL_PATH_ID, local_addr, local_addrlen, peer_addr, peer_addrlen); @@ -1197,15 +1199,6 @@ xqc_conn_server_create(xqc_engine_t *engine, const struct sockaddr *local_addr, xqc_log_event(conn->log, CON_CONNECTION_STARTED, conn, XQC_LOG_REMOTE_EVENT); - if (conn->transport_cbs.server_accept) { - if (conn->transport_cbs.server_accept(engine, conn, &conn->scid_set.user_scid, user_data) < 0) { - xqc_log(engine->log, XQC_LOG_ERROR, "|server_accept callback return error|"); - XQC_CONN_ERR(conn, TRA_CONNECTION_REFUSED_ERROR); - goto fail; - } - conn->conn_flag |= XQC_CONN_FLAG_UPPER_CONN_EXIST; - } - return conn; fail: @@ -1378,7 +1371,7 @@ xqc_common_conn_info_print(xqc_connection_t *conn, char *output, size_t output_s ret = snprintf(output, output_size, "%d,%"PRIu64",%"PRIu64",%"PRIu64",%d," , - conn->conn_video_frames, + conn->conn_calculated_frames, conn->conn_avg_close_delay / 1000, conn->conn_avg_recv_delay / 1000, conn->conn_latest_close_delay / 1000, @@ -1562,14 +1555,28 @@ xqc_conn_destroy(xqc_connection_t *xc) } /* notify destruction */ - if (xc->conn_flag & XQC_CONN_FLAG_UPPER_CONN_EXIST) { + if (xc->conn_type == XQC_CONN_TYPE_CLIENT) { /* client close connection */ + if ((xc->conn_flag & XQC_CONN_FLAG_UPPER_CONN_EXIST) + && xc->app_proto_cbs.conn_cbs.conn_close_notify) { + xc->app_proto_cbs.conn_cbs.conn_close_notify(xc, &xc->scid_set.user_scid, + xc->user_data, + xc->proto_data); + } else { + xqc_log(xc->log, XQC_LOG_REPORT, + "|conn close event not notified|%s", xqc_conn_addr_str(xc)); + } + } else { /* server close connection */ /* ALPN negotiated, notify close through application layer protocol callback function */ - if (xc->app_proto_cbs.conn_cbs.conn_close_notify) { + if ((xc->conn_flag & XQC_CONN_FLAG_UPPER_CONN_EXIST) + && xc->app_proto_cbs.conn_cbs.conn_close_notify) + { xc->app_proto_cbs.conn_cbs.conn_close_notify(xc, &xc->scid_set.user_scid, xc->user_data, xc->proto_data); - } else if (xc->transport_cbs.server_refuse) { + } else if (xc->conn_flag & XQC_CONN_FLAG_SERVER_ACCEPT + && xc->transport_cbs.server_refuse) + { /* ALPN context is not initialized, ClientHello has not been received */ xc->transport_cbs.server_refuse(xc->engine, xc, &xc->scid_set.user_scid, xc->user_data); xqc_log(xc->log, XQC_LOG_REPORT, @@ -1579,9 +1586,9 @@ xqc_conn_destroy(xqc_connection_t *xc) xqc_log(xc->log, XQC_LOG_REPORT, "|conn close event not notified|%s", xqc_conn_addr_str(xc)); } - - xc->conn_flag &= ~XQC_CONN_FLAG_UPPER_CONN_EXIST; + xc->conn_flag &= ~XQC_CONN_FLAG_SERVER_ACCEPT; } + xc->conn_flag &= ~XQC_CONN_FLAG_UPPER_CONN_EXIST; /* destroy gp_timer list */ xqc_timer_destroy_gp_timer_list(&xc->conn_timer_manager); @@ -2484,7 +2491,7 @@ xqc_conn_enc_packet(xqc_connection_t *conn, ssize_t xqc_send(xqc_connection_t *conn, xqc_path_ctx_t *path, unsigned char *data, unsigned int len) { - ssize_t sent; + ssize_t sent = -XQC_ESOCKET; if (conn->pkt_filter_cb) { sent = conn->pkt_filter_cb(data, len, (struct sockaddr *)conn->peer_addr, @@ -2496,8 +2503,28 @@ xqc_send(xqc_connection_t *conn, xqc_path_ctx_t *path, unsigned char *data, unsi return sent == XQC_SOCKET_EAGAIN ? -XQC_EAGAIN : -XQC_EPACKET_FILETER_CALLBACK; } sent = len; - - } else if (conn->transport_cbs.write_socket_ex) { + xqc_log_event(conn->log, TRA_DATAGRAMS_SENT, sent, path->path_id); + return sent; + } + if (conn->conn_type == XQC_CONN_TYPE_SERVER && !(conn->conn_flag & XQC_CONN_FLAG_SERVER_ACCEPT)) { + if (conn->transport_cbs.conn_send_packet_before_accept) { + sent = + conn->transport_cbs.conn_send_packet_before_accept(data, len, (struct sockaddr *)path->peer_addr, + path->peer_addrlen, + xqc_conn_get_user_data(conn)); + if (sent != len) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|send packet before accept error|conn:%p|size:%ud|sent:%z|", conn, len, sent); + return -XQC_ESOCKET; /* EAGAIN same as error */ + } + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|conn_send_packet_before_accept NULL|"); + } + xqc_log_event(conn->log, TRA_DATAGRAMS_SENT, sent, path->path_id); + return sent; + } + + if (conn->transport_cbs.write_socket_ex) { sent = conn->transport_cbs.write_socket_ex(path->path_id, data, len, (struct sockaddr *)path->peer_addr, path->peer_addrlen, @@ -3238,26 +3265,53 @@ xqc_conn_send_retry(xqc_connection_t *conn, unsigned char *token, unsigned token { xqc_engine_t *engine = conn->engine; unsigned char buf[XQC_PACKET_OUT_BUF_CAP]; - xqc_int_t size = (xqc_int_t)xqc_gen_retry_packet(buf, + if (conn->transport_cbs.conn_send_packet_before_accept == NULL) { + xqc_log(engine->log, XQC_LOG_WARN, "|xqc_conn_send_retry|" + "send retry packet failed, conn_send_packet_before_accept is NULL|"); + return XQC_ERROR; + } + + if (xqc_generate_cid(engine, &conn->original_dcid, &conn->retry_scid, 0) != XQC_OK) { + xqc_log(engine->log, XQC_LOG_WARN, "|xqc_conn_send_retry|" + "generate retry scid failed|"); + return XQC_ERROR; + } + + + xqc_int_t size = (xqc_int_t)xqc_gen_retry_packet(conn, buf, conn->dcid_set.current_dcid.cid_buf, conn->dcid_set.current_dcid.cid_len, - conn->scid_set.user_scid.cid_buf, - conn->scid_set.user_scid.cid_len, + conn->retry_scid.cid_buf, + conn->retry_scid.cid_len, conn->original_dcid.cid_buf, conn->original_dcid.cid_len, token, token_len, XQC_VERSION_V1); if (size < 0) { - return size; + xqc_log(engine->log, XQC_LOG_WARN, "|xqc_conn_send_retry|generate retry packet failed|" + "size:%d|", size); + return XQC_ERROR; } - size = (xqc_int_t)conn->transport_cbs.write_socket( + ssize_t send = conn->transport_cbs.conn_send_packet_before_accept( buf, (size_t)size, (struct sockaddr*)conn->peer_addr, conn->peer_addrlen, xqc_conn_get_user_data(conn)); - if (size < 0) { - return size; + + if (send != size) { + xqc_log(engine->log, XQC_LOG_WARN, "|xqc_conn_send_retry|send retry packet failed|" + "size:%d|send:%d|", size, send); + return XQC_ERROR; } + /* retry scid insert into the conns_hash after send the retry packet successfully*/ + if (xqc_insert_conns_hash(conn->engine->conns_hash, conn, + conn->retry_scid.cid_buf, conn->retry_scid.cid_len)) + { + xqc_log(conn->log, XQC_LOG_ERROR, "|insert retry_scid failed|"); + return XQC_ERROR; + } + conn->conn_flag |= XQC_CONN_FLAG_RETRY_SENT; + xqc_log(engine->log, XQC_LOG_INFO, "|<==|xqc_conn_send_retry ok|size:%d|", size); return XQC_OK; } @@ -3281,13 +3335,6 @@ xqc_conn_version_check(xqc_connection_t *c, uint32_t version) for (i = XQC_IDRAFT_INIT_VER + 1; i < XQC_IDRAFT_VER_NEGOTIATION; i++) { if (xqc_proto_version_value[i] == version) { c->version = i; - - xqc_int_t ret = xqc_tls_init(c->tls, c->version, &c->original_dcid); - if (ret != XQC_OK) { - xqc_log(c->log, XQC_LOG_ERROR, "|init tls error|"); - return ret; - } - return XQC_OK; } } @@ -3357,6 +3404,7 @@ xqc_conn_send_version_negotiation(xqc_connection_t *c) return XQC_OK; } + void xqc_conn_continue_send_by_conn(xqc_connection_t *conn) { @@ -3763,17 +3811,85 @@ xqc_conn_get_lastest_rtt(xqc_engine_t *engine, const xqc_cid_t *cid) xqc_int_t -xqc_conn_check_token(xqc_connection_t *conn, const unsigned char *token, unsigned token_len) +xqc_conn_decrypt_token(xqc_connection_t *conn, unsigned char *dec_data, unsigned int *d_len, + const unsigned char *enc_data, unsigned e_len) { - if (token_len > XQC_MAX_TOKEN_LEN) { - xqc_log(conn->log, XQC_LOG_ERROR, "|%ud exceed XQC_MAX_TOKEN_LEN|", token_len); + if (e_len <= XQC_TOKEN_IV_LEN + XQC_TOKEN_TAG_LEN + 1) { + xqc_log(conn->log, XQC_LOG_ERROR, "|token length too small|%ud|", e_len); + return XQC_ERROR; + } + + const EVP_CIPHER *cipher = EVP_aes_128_gcm(); + int len, tmp_len; + + /* random iv */ + const unsigned char *iv = enc_data; + + /* flag do not encrypt */ + uint8_t flag = enc_data[XQC_TOKEN_IV_LEN]; + dec_data[0] = flag; + *d_len = 1; + + uint8_t cur_ts_index = flag & XQC_TOKEN_VERSION_MASK; + unsigned char *key = conn->engine->token_secret_list[cur_ts_index]; + + const unsigned char *p_enc = enc_data + XQC_TOKEN_IV_LEN + 1; + unsigned char *p_dec = dec_data + 1; + len = e_len - XQC_TOKEN_IV_LEN - XQC_TOKEN_TAG_LEN - 1; + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|decrypt token create cipher ctx error|"); return XQC_ERROR; + } + if (XQC_SSL_SUCCESS != EVP_DecryptInit_ex(ctx, cipher, NULL, key, iv)) { + xqc_log(conn->log, XQC_LOG_ERROR, "|EVP_DecryptInit_ex failed|"); + goto error; + } - } else if (token_len == 0) { + if (XQC_SSL_SUCCESS != EVP_DecryptUpdate(ctx, p_dec, &tmp_len, p_enc, len)) { + xqc_log(conn->log, XQC_LOG_ERROR, "|EVP_DecryptUpdate failed|"); + goto error; + } + *d_len += tmp_len; + if (XQC_SSL_SUCCESS != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, XQC_TOKEN_TAG_LEN, (void *)(p_enc + len))) { + xqc_log(conn->log, XQC_LOG_ERROR, "|EVP_CIPHER_CTX_ctrl failed|"); + goto error; + } + if (XQC_SSL_SUCCESS != EVP_DecryptFinal_ex(ctx, p_dec + tmp_len, &tmp_len)) { + xqc_log(conn->log, XQC_LOG_ERROR, "|EVP_DecryptFinal_ex failed|"); + goto error; + } + *d_len += tmp_len; + + EVP_CIPHER_CTX_free(ctx); + return XQC_OK; + +error: + if (ctx) { + EVP_CIPHER_CTX_free(ctx); + } + return XQC_ERROR; +} + +xqc_int_t +xqc_conn_check_token(xqc_connection_t *conn, const unsigned char *enc_data, unsigned e_len) +{ + if (e_len > XQC_MAX_TOKEN_LEN) { + xqc_log(conn->log, XQC_LOG_ERROR, "|%ud exceed XQC_MAX_TOKEN_LEN|", e_len); + return XQC_ERROR; + + } else if (e_len == 0) { xqc_log(conn->log, XQC_LOG_INFO, "|token empty|"); return XQC_ERROR; } + unsigned char token[XQC_MAX_TOKEN_LEN]; + unsigned int token_len = 0; + if (XQC_OK != xqc_conn_decrypt_token(conn, token, &token_len, enc_data, e_len)) { + xqc_log(conn->log, XQC_LOG_WARN, "|token decrypt error|"); + return XQC_ERROR; + } + struct sockaddr *sa = (struct sockaddr *)conn->peer_addr; const unsigned char *pos = token; if (*pos++ & 0x80) { @@ -3823,22 +3939,13 @@ xqc_conn_check_token(xqc_connection_t *conn, const unsigned char *token, unsigne return XQC_OK; } -/* - * +-+-+-+-+-+-+-+-+ - * |v|0|0|0|0|0|0|0| - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | IP(32/128) | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Expire Time(32) | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * v: 0 For IPv4, 1 For IPv6 - */ void -xqc_conn_gen_token(xqc_connection_t *conn, unsigned char *token, unsigned *token_len) +xqc_conn_generate_plain_token(xqc_connection_t *conn, uint8_t ts_index, unsigned char *token, + unsigned *token_len, uint32_t expire) { struct sockaddr *sa = (struct sockaddr *)conn->peer_addr; if (sa->sa_family == AF_INET) { - *token++ = 0x00; + *token++ = (0x00 | ts_index); struct sockaddr_in *sa4 = (struct sockaddr_in *)sa; memcpy(token, &sa4->sin_addr, sizeof(struct in_addr)); token += sizeof(struct in_addr); @@ -3846,18 +3953,123 @@ xqc_conn_gen_token(xqc_connection_t *conn, unsigned char *token, unsigned *token *token_len = 9; } else { - *token++ = 0x80; + *token++ = (0x80 | ts_index); struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; memcpy(token, &sa6->sin6_addr, sizeof(struct in6_addr)); token += sizeof(struct in6_addr); *token_len = 21; } + memcpy(token, &expire, sizeof(expire)); +} + + + +/* + * + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * RANDOM IV(96-bit) + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * +-+-+-+-+-+-+-+-+ + * |v|0|0|0|0|0|2bit rotating version| + * +-+-+-+-+-+-+-+-+ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | IP(32/128) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Expire Time(32) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * v: 0 For IPv4, 1 For IPv6, rotating version for token key update + */ + +xqc_int_t +xqc_conn_generate_and_encrypt_token(xqc_connection_t *conn, unsigned char *token, + unsigned *token_len, uint32_t expire) +{ + unsigned char plain_text[XQC_MAX_TOKEN_LEN - XQC_TOKEN_IV_LEN - XQC_TOKEN_TAG_LEN]; + unsigned int len = sizeof(plain_text); + uint8_t cur_ts_index = conn->engine->cur_ts_index; + xqc_conn_generate_plain_token(conn, cur_ts_index, plain_text, &len, expire); + if (len + XQC_TOKEN_IV_LEN + XQC_TOKEN_TAG_LEN > *token_len) { + xqc_log(conn->log, XQC_LOG_ERROR, "|generate token length invalid|"); + return XQC_ERROR; + } + + char *iv = token, *crypto_p = token + XQC_TOKEN_IV_LEN + 1, *plain_p = &plain_text[1]; + unsigned int plain_len = len - 1; + const unsigned char *key = conn->engine->token_secret_list[cur_ts_index]; + if (RAND_bytes(iv, XQC_TOKEN_IV_LEN) == 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|generate iv error|"); + return XQC_ERROR; + } + *token_len = XQC_TOKEN_IV_LEN; + token[XQC_TOKEN_IV_LEN] = plain_text[0]; + *token_len += 1; + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|create evp_cipher_ctx error|"); + return XQC_ERROR; + } + const EVP_CIPHER *cipher = EVP_aes_128_gcm(); + if (XQC_SSL_SUCCESS != EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv)) { + xqc_log(conn->log, XQC_LOG_ERROR, "|generate iv error|"); + goto error; + } + + if (XQC_SSL_SUCCESS != EVP_EncryptUpdate(ctx, crypto_p, &len, plain_p, plain_len)) { + xqc_log(conn->log, XQC_LOG_ERROR, "|EVP_EncryptUpdate error|"); + goto error; + } + *token_len += len; + + if (XQC_SSL_SUCCESS != EVP_EncryptFinal_ex(ctx, token + *token_len, &len)) { + xqc_log(conn->log, XQC_LOG_ERROR, "|EVP_EncryptFinal_ex error|"); + goto error; + } + *token_len += len; + if (XQC_SSL_SUCCESS != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, XQC_TOKEN_TAG_LEN, token + *token_len)) { + goto error; + } + *token_len += XQC_TOKEN_TAG_LEN; + + EVP_CIPHER_CTX_free(ctx); + return XQC_OK; +error: + if (ctx) { + EVP_CIPHER_CTX_free(ctx); + } + return XQC_ERROR; + +} + +xqc_int_t +xqc_conn_gen_token(xqc_connection_t *conn, unsigned char *token, unsigned *token_len) +{ uint32_t expire = xqc_monotonic_timestamp() / 1000000 + XQC_TOKEN_EXPIRE_DELTA; xqc_log(conn->log, XQC_LOG_DEBUG, "|expire:%ud|", expire); expire = htonl(expire); - memcpy(token, &expire, sizeof(expire)); + return xqc_conn_generate_and_encrypt_token(conn, token, token_len ,expire); +} + +xqc_int_t +xqc_conn_gen_retry_token(xqc_connection_t *conn, unsigned char *token, unsigned *token_len) +{ + uint32_t expire = xqc_monotonic_timestamp() / 1000000 + XQC_TOKEN_RETRY_PACKET_EXPIRE_DELTA; + expire = htonl(expire); + return xqc_conn_generate_and_encrypt_token(conn, token, token_len, expire); +} + +xqc_int_t +xqc_conn_send_retry_packet(xqc_connection_t *conn) +{ + unsigned char token[XQC_MAX_TOKEN_LEN]; + unsigned token_len = XQC_MAX_TOKEN_LEN; + if (xqc_conn_gen_retry_token(conn, token, &token_len) != XQC_OK) { + xqc_log(conn->log, XQC_LOG_WARN, "|gen retry token failed|"); + return XQC_ERROR; + } + return xqc_conn_send_retry(conn, token, token_len); } void @@ -3944,6 +4156,72 @@ xqc_conn_early_data_reject(xqc_connection_t *conn) return XQC_OK; } +/* + * server accept when server receive first initial packet + * check retry packet condition first and send retry packet if needed + */ +xqc_int_t +xqc_conn_server_accept(xqc_connection_t *c) +{ + xqc_int_t ret = XQC_OK; + /* check whether to send retry packet */ + if (!(c->conn_flag & XQC_CONN_FLAG_TOKEN_OK)) { + /* validate token with Initial packet before server_accept called */ + if (xqc_conn_check_token(c, c->conn_token, c->conn_token_len) == XQC_OK) { + c->conn_flag |= XQC_CONN_FLAG_TOKEN_OK; + + } else if (c->version != XQC_IDRAFT_VER_29) { /* IDRAFT_VER_29 is too old to send retry packet */ + xqc_log(c->log, XQC_LOG_INFO, "|check_token fail|conn:%p|%s|", c, xqc_conn_addr_str(c)); + if (c->conn_flag & XQC_CONN_FLAG_RETRY_SENT) { + return -XQC_EIGNORE_PKT; /* retry packet already sent */ + } else { + if (c->transport_cbs.conn_retry_packet_condition_check) { + if (c->transport_cbs.conn_retry_packet_condition_check(c->engine, + c, &c->scid_set.user_scid, c->user_data) == XQC_TRUE) + { + ret = xqc_conn_send_retry_packet(c); + if (ret == XQC_OK) { + return -XQC_EIGNORE_PKT; /* send retry packet, then ignore this packet */ + } else { + xqc_log(c->log, XQC_LOG_ERROR, "|send retry packet failed|"); + return -XQC_ESEND_RETRY; + } + } + } + } + } + } + + /* create and initial server tls */ + ret = xqc_conn_create_server_tls(c); + if (ret != XQC_OK) { + xqc_log(c->log, XQC_LOG_ERROR, "|create server tls error|"); + return -XQC_TLS_FATAL; + } + if (c->conn_flag & XQC_CONN_FLAG_RETRY_SENT) { + ret = xqc_tls_init(c->tls, c->version, &c->retry_scid); + } else { + ret = xqc_tls_init(c->tls, c->version, &c->original_dcid); + } + if (ret != XQC_OK) { + xqc_log(c->log, XQC_LOG_ERROR, "|init tls error|"); + return -XQC_TLS_FATAL; + } + + if (c->transport_cbs.server_accept) { + ret = c->transport_cbs.server_accept(c->engine, c, &c->scid_set.user_scid, c->user_data); + if (ret != XQC_OK) { + xqc_log(c->log, XQC_LOG_ERROR, "|server_accept callback return error|"); + XQC_CONN_ERR(c, TRA_CONNECTION_REFUSED_ERROR); + return -XQC_ECREATE_CONN; + } + c->conn_flag |= XQC_CONN_FLAG_SERVER_ACCEPT; + } + + return ret; +} + + xqc_int_t xqc_conn_early_data_accept(xqc_connection_t *conn) { @@ -4869,6 +5147,17 @@ xqc_conn_destroy_cids(xqc_connection_t *conn) conn->original_dcid.cid_buf, conn->original_dcid.cid_len); } + + if (conn->conn_flag & XQC_CONN_FLAG_RETRY_SENT) { + if (xqc_find_conns_hash(conn->engine->conns_hash, conn, + conn->retry_scid.cid_buf, + conn->retry_scid.cid_len)) + { + xqc_remove_conns_hash(conn->engine->conns_hash, conn, + conn->retry_scid.cid_buf, + conn->retry_scid.cid_len); + } + } xqc_list_for_each_safe(pos_set, next_set, &conn->scid_set.cid_set_list) { inner_set = xqc_list_entry(pos_set, xqc_cid_set_inner_t, next); @@ -5330,7 +5619,6 @@ xqc_conn_on_recv_retry(xqc_connection_t *conn, xqc_cid_t *retry_scid) /* change the DCID it uses for sending packets in response to Retry packet. */ xqc_cid_copy(&conn->dcid_set.current_dcid, retry_scid); xqc_datagram_record_mss(conn); - /* reset initial keys */ ret = xqc_tls_reset_initial(conn->tls, conn->version, retry_scid); if (ret != XQC_OK) { @@ -5339,7 +5627,6 @@ xqc_conn_on_recv_retry(xqc_connection_t *conn, xqc_cid_t *retry_scid) xqc_scid_str(conn->engine, retry_scid), ret); return ret; } - /* * clients that receive a Retry packet reset congestion control and loss * recovery state, including resetting any pending timers. @@ -5550,9 +5837,18 @@ xqc_conn_get_local_transport_params(xqc_connection_t *conn, xqc_transport_params conn->initial_scid.cid_buf, conn->initial_scid.cid_len); params->initial_source_connection_id_present = 1; - params->retry_source_connection_id.cid_len = 0; - params->retry_source_connection_id_present = 0; - + if (conn->conn_type == XQC_CONN_TYPE_SERVER + && conn->conn_flag & XQC_CONN_FLAG_RETRY_SENT + && conn->retry_scid.cid_len > 0) + { + xqc_cid_set(¶ms->retry_source_connection_id, + conn->retry_scid.cid_buf, conn->retry_scid.cid_len); + params->retry_source_connection_id_present = 1; + + } else { + params->retry_source_connection_id.cid_len = 0; + params->retry_source_connection_id_present = 0; + } params->conn_option_num = settings->conn_option_num; xqc_memcpy(params->conn_options, settings->conn_options, sizeof(uint32_t) * settings->conn_option_num); @@ -6044,6 +6340,19 @@ xqc_conn_tls_cert_cb(const char *sni, void **chain, void **crt, return XQC_OK; } + +void +xqc_conn_tls_msg_cb(int msg_type, + const void *msg, size_t msg_len, void *user_data) +{ + xqc_connection_t *conn = (xqc_connection_t *)user_data; + + if (conn->transport_cbs.conn_ssl_msg_cb) { + return conn->transport_cbs.conn_ssl_msg_cb(msg_type, msg, + msg_len, conn->user_data); + } +} + void xqc_conn_tls_handshake_completed_cb(void *user_data) { @@ -6063,8 +6372,16 @@ const xqc_tls_callbacks_t xqc_conn_tls_cbs = { .error_cb = xqc_conn_tls_error_cb, .hsk_completed_cb = xqc_conn_tls_handshake_completed_cb, .cert_cb = xqc_conn_tls_cert_cb, + .msg_cb = xqc_conn_tls_msg_cb, }; +/* init_idle_time_out millisecond */ +void +xqc_conn_set_init_idle_timeout(xqc_connection_t *conn, xqc_msec_t init_idle_time_out) +{ + conn->conn_settings.init_idle_time_out = init_idle_time_out; +} + xqc_msec_t xqc_conn_get_idle_timeout(xqc_connection_t *conn) { diff --git a/src/transport/xqc_conn.h b/src/transport/xqc_conn.h index a92b5e522..207f9cc54 100644 --- a/src/transport/xqc_conn.h +++ b/src/transport/xqc_conn.h @@ -32,6 +32,7 @@ #define XQC_TOKEN_EXPIRE_DELTA (7 * 24 * 60 * 60) /* expire in N seconds */ #define XQC_TOKEN_UPDATE_DELTA (XQC_TOKEN_EXPIRE_DELTA / 2) /* early update */ +#define XQC_TOKEN_RETRY_PACKET_EXPIRE_DELTA 5 /* retry packet token's expire time */ /* maximum accumulated number of xqc_engine_packet_process */ #define XQC_MAX_PACKET_PROCESS_BATCH 100 @@ -136,7 +137,9 @@ typedef enum { XQC_CONN_FLAG_MP_WAIT_MP_READY_SHIFT = 38, XQC_CONN_FLAG_MP_READY_NOTIFY_SHIFT = 39, XQC_CONN_FLAG_HANDSHAKE_DONE_SENT_SHIFT = 40, - XQC_CONN_FLAG_SHIFT_NUM = 41, + XQC_CONN_FLAG_SERVER_ACCEPT_SHIFT = 41, + XQC_CONN_FLAG_RETRY_SENT_SHIFT = 42, + XQC_CONN_FLAG_SHIFT_NUM } xqc_conn_flag_shift_t; typedef enum { @@ -181,7 +184,8 @@ typedef enum { XQC_CONN_FLAG_MP_WAIT_MP_READY = 1ULL << XQC_CONN_FLAG_MP_WAIT_MP_READY_SHIFT, XQC_CONN_FLAG_MP_READY_NOTIFY = 1ULL << XQC_CONN_FLAG_MP_READY_NOTIFY_SHIFT, XQC_CONN_FLAG_HANDSHAKE_DONE_SENT = 1ULL << XQC_CONN_FLAG_HANDSHAKE_DONE_SENT_SHIFT, - + XQC_CONN_FLAG_SERVER_ACCEPT = 1ULL << XQC_CONN_FLAG_SERVER_ACCEPT_SHIFT, + XQC_CONN_FLAG_RETRY_SENT = 1ULL << XQC_CONN_FLAG_RETRY_SENT_SHIFT, } xqc_conn_flag_t; @@ -285,6 +289,9 @@ struct xqc_connection_s { /* initial source connection id, RFC 9000, Section 7.3 */ xqc_cid_t initial_scid; + /* retry source connection id, RFC 9000, Section 7.3 */ + xqc_cid_t retry_scid; + xqc_cid_set_t dcid_set; xqc_cid_set_t scid_set; @@ -492,7 +499,7 @@ struct xqc_connection_s { xqc_usec_t conn_avg_close_delay; xqc_usec_t conn_avg_recv_delay; xqc_usec_t conn_latest_close_delay; - uint32_t conn_video_frames; + uint32_t conn_calculated_frames; }; extern const xqc_h3_conn_settings_t default_local_h3_conn_settings; @@ -539,7 +546,7 @@ xqc_int_t xqc_conn_send_retry(xqc_connection_t *conn, unsigned char *token, unsi xqc_int_t xqc_conn_version_check(xqc_connection_t *c, uint32_t version); xqc_int_t xqc_conn_send_version_negotiation(xqc_connection_t *c); xqc_int_t xqc_conn_check_token(xqc_connection_t *conn, const unsigned char *token, unsigned token_len); -void xqc_conn_gen_token(xqc_connection_t *conn, unsigned char *token, unsigned *token_len); +xqc_int_t xqc_conn_gen_token(xqc_connection_t *conn, unsigned char *token, unsigned *token_len); xqc_int_t xqc_conn_early_data_reject(xqc_connection_t *conn); xqc_int_t xqc_conn_early_data_accept(xqc_connection_t *conn); xqc_bool_t xqc_conn_is_ready_to_send_early_data(xqc_connection_t *conn); @@ -711,6 +718,8 @@ void xqc_path_send_packets(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_int_t xqc_conn_try_to_enable_multipath(xqc_connection_t *conn); xqc_int_t xqc_conn_add_path_cid_sets(xqc_connection_t *conn, uint32_t start, uint32_t end); xqc_msec_t xqc_conn_get_queue_fin_timeout(xqc_connection_t *conn); +void xqc_conn_set_init_idle_timeout(xqc_connection_t *conn, xqc_msec_t init_idle_time_out); void xqc_conn_try_to_enable_pmtud(xqc_connection_t *conn); +xqc_int_t xqc_conn_server_accept(xqc_connection_t *c); #endif /* _XQC_CONN_H_INCLUDED_ */ diff --git a/src/transport/xqc_defs.h b/src/transport/xqc_defs.h index 1a406b082..2dd56362f 100644 --- a/src/transport/xqc_defs.h +++ b/src/transport/xqc_defs.h @@ -49,6 +49,10 @@ /* max token length supported by xquic */ #define XQC_MAX_TOKEN_LEN 256 +#define XQC_TOKEN_IV_LEN 12 +#define XQC_TOKEN_TAG_LEN 16 +/* EVP_aes_128_gcm secret len */ +#define XQC_TOKEN_SECRET_LEN 16 /* length of retry integrity tag */ #define XQC_RETRY_INTEGRITY_TAG_LEN 16 @@ -71,4 +75,4 @@ extern const unsigned char xqc_proto_version_field[][XQC_PROTO_VERSION_LEN]; #define XQC_MAX_MT_ROW 256 #define XQC_RSM_COL 48 -#endif \ No newline at end of file +#endif diff --git a/src/transport/xqc_engine.c b/src/transport/xqc_engine.c index 896cbb6cc..e9db56ba5 100644 --- a/src/transport/xqc_engine.c +++ b/src/transport/xqc_engine.c @@ -27,7 +27,7 @@ #include "src/transport/xqc_reinjection.h" #include "src/transport/xqc_packet_out.h" - +#define XQC_DEFAULT_TOKEN_KEY "xquic token key" extern const xqc_qpack_ins_cb_t xqc_h3_qpack_ins_cb; xqc_config_t default_client_config = { @@ -132,6 +132,22 @@ xqc_set_config(xqc_config_t *dst, const xqc_config_t *src) memcpy(dst->reset_token_key, src->reset_token_key, src->reset_token_keylen); } } + + for (int i = 0; i < XQC_TOKEN_MAX_KEY_VERSION; i++) { + int tk_len = src->tk_len_list[i]; + if (tk_len > 0 && tk_len < XQC_TOKEN_MAX_KEY_LEN) { + dst->tk_len_list[i] = tk_len; + memcpy(dst->token_key_list[i], src->token_key_list[i], tk_len); + } else { + dst->tk_len_list[i] = sizeof(XQC_DEFAULT_TOKEN_KEY) - 1; + memcpy(dst->token_key_list[i], XQC_DEFAULT_TOKEN_KEY, dst->tk_len_list[i]); + } + } + if (src->cur_tk_index < XQC_TOKEN_MAX_KEY_VERSION) { + dst->cur_tk_index = src->cur_tk_index; + } else { + return XQC_ERROR; + } dst->cid_negotiate = src->cid_negotiate; dst->cfg_log_level = src->cfg_log_level; @@ -145,6 +161,15 @@ xqc_set_config(xqc_config_t *dst, const xqc_config_t *src) return XQC_OK; } +void +xqc_engine_initial_token_secret(unsigned char *src, uint16_t src_len, unsigned char *dst) +{ + xqc_md5_t ctx; + xqc_md5_init(&ctx); + xqc_md5_update(&ctx, src, src_len); + xqc_md5_final(dst, &ctx); +} + xqc_int_t xqc_engine_get_default_config(xqc_config_t *config, xqc_engine_type_t engine_type) @@ -161,7 +186,19 @@ xqc_engine_get_default_config(xqc_config_t *config, xqc_engine_type_t engine_typ xqc_int_t xqc_engine_set_config(xqc_engine_t *engine, const xqc_config_t *engine_config) { - return xqc_set_config(engine->config, engine_config); + xqc_int_t ret = xqc_set_config(engine->config, engine_config); + if (ret != XQC_OK) { + return ret; + } + if (engine->eng_type == XQC_ENGINE_SERVER) { + engine->cur_ts_index = engine->config->cur_tk_index & XQC_TOKEN_VERSION_MASK; + for (int i = 0; i < XQC_TOKEN_MAX_KEY_VERSION; i++) { + xqc_engine_initial_token_secret(engine->config->token_key_list[i], + engine->config->tk_len_list[i], + engine->token_secret_list[i]); + } + } + return XQC_OK; } @@ -1201,6 +1238,7 @@ xqc_engine_packet_process(xqc_engine_t *engine, /* NAT rebinding */ if (engine->eng_type == XQC_ENGINE_SERVER + && (conn->conn_flag & XQC_CONN_FLAG_SERVER_ACCEPT) && (peer_addr != NULL && peer_addrlen != 0) && !xqc_is_same_addr_as_any_path(conn, peer_addr)) { @@ -1477,9 +1515,16 @@ xqc_engine_free_alpn_list(xqc_engine_t *engine) xqc_bool_t xqc_engine_is_sendmmsg_on(xqc_engine_t *engine, xqc_connection_t *conn) { - return engine->config->sendmmsg_on - && (engine->transport_cbs.write_mmsg || engine->transport_cbs.write_mmsg_ex) - && (!conn->conn_settings.disable_send_mmsg); + if (engine->eng_type == XQC_ENGINE_SERVER) { + return engine->config->sendmmsg_on + && (engine->transport_cbs.write_mmsg || engine->transport_cbs.write_mmsg_ex) + && (!conn->conn_settings.disable_send_mmsg) + && (conn->conn_flag & XQC_CONN_FLAG_SERVER_ACCEPT); + } else { + return engine->config->sendmmsg_on + && (engine->transport_cbs.write_mmsg || engine->transport_cbs.write_mmsg_ex) + && (!conn->conn_settings.disable_send_mmsg); + } } diff --git a/src/transport/xqc_engine.h b/src/transport/xqc_engine.h index fc8d8ef45..ccdc49766 100644 --- a/src/transport/xqc_engine.h +++ b/src/transport/xqc_engine.h @@ -11,7 +11,7 @@ #include #include "src/tls/xqc_tls.h" #include "src/common/xqc_list.h" - +#include "src/transport/xqc_defs.h" #define XQC_RESET_CNT_ARRAY_LEN 16384 @@ -80,7 +80,9 @@ typedef struct xqc_engine_s { char peer_addr_str[INET6_ADDRSTRLEN]; void *priv_ctx; - + unsigned char token_secret_list[XQC_TOKEN_MAX_KEY_VERSION][XQC_TOKEN_SECRET_LEN]; + uint8_t cur_ts_index; + } xqc_engine_t; diff --git a/src/transport/xqc_fec.c b/src/transport/xqc_fec.c index 24346b278..48f0a306b 100644 --- a/src/transport/xqc_fec.c +++ b/src/transport/xqc_fec.c @@ -1571,4 +1571,23 @@ xqc_fec_on_stream_size_changed(xqc_stream_t *quic_stream) conn->conn_settings.fec_params.fec_max_symbol_num_per_block = src_syb_num; conn->conn_settings.fec_callback.xqc_fec_init_one(conn, 0); } -} \ No newline at end of file +} + +void +xqc_record_fec_state(xqc_stream_t *stream) +{ + xqc_int_t enable_stream_num; + xqc_usec_t curr_recv_delay, curr_fec_recv_opt; + xqc_usec_t curr_close_delay; + if (stream->stream_conn->fec_ctl == NULL) { + return; + } + +#define __calc_delay(a, b) ((a && b && (a > b))? (a) - (b) : 0) + enable_stream_num = stream->stream_conn->fec_ctl->fec_enable_stream_num++; + curr_recv_delay = __calc_delay(stream->stream_stats.recv_time_with_fec, stream->stream_stats.create_time); + curr_fec_recv_opt = __calc_delay(stream->stream_stats.final_packet_time, stream->stream_stats.recv_time_with_fec); + stream->stream_conn->fec_ctl->conn_avg_recv_delay = xqc_update_avg_time(curr_recv_delay, stream->stream_conn->fec_ctl->conn_avg_recv_delay, enable_stream_num); + stream->stream_conn->fec_ctl->fec_avg_opt_time = xqc_update_avg_time(curr_fec_recv_opt, stream->stream_conn->fec_ctl->fec_avg_opt_time, enable_stream_num); +#undef __calc_delay +} diff --git a/src/transport/xqc_fec.h b/src/transport/xqc_fec.h index 29c39262a..541a40832 100644 --- a/src/transport/xqc_fec.h +++ b/src/transport/xqc_fec.h @@ -220,4 +220,6 @@ xqc_int_t xqc_send_repair_packets(xqc_connection_t *conn, xqc_fec_schemes_e sche xqc_int_t xqc_process_fec_protected_packet_moq(xqc_stream_t *stream); void xqc_fec_on_stream_size_changed(xqc_stream_t *quic_stream); + +void xqc_record_fec_state(xqc_stream_t *stream); #endif /* _XQC_FEC_H_INCLUDED_ */ \ No newline at end of file diff --git a/src/transport/xqc_frame.c b/src/transport/xqc_frame.c index a60642a2f..559a8a120 100644 --- a/src/transport/xqc_frame.c +++ b/src/transport/xqc_frame.c @@ -497,6 +497,7 @@ xqc_process_stream_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) if (packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) { stream->stream_stats.recov_pkt_cnt++; + stream->stream_fec_ctl.enable_fec = 1; if (stream->stream_stats.fec_blk_lack_time == 0) { stream->stream_stats.fec_blk_lack_time = xqc_calc_delay(xqc_monotonic_timestamp(), packet_in->pi_fec_process_time); } @@ -689,19 +690,6 @@ xqc_process_crypto_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) /* ack even if the token check fail */ packet_in->pi_frame_types |= XQC_FRAME_BIT_CRYPTO; - /* check token, only validate token with Initial/CRYPTO packet, but not with Initial/ACK */ - if (!(conn->conn_flag & XQC_CONN_FLAG_TOKEN_OK) - && conn->conn_type == XQC_CONN_TYPE_SERVER - && packet_in->pi_pkt.pkt_type == XQC_PTYPE_INIT) - { - if (xqc_conn_check_token(conn, conn->conn_token, conn->conn_token_len) == XQC_OK) { - conn->conn_flag |= XQC_CONN_FLAG_TOKEN_OK; - - } else { - xqc_log(conn->log, XQC_LOG_INFO, "|check_token fail|conn:%p|%s|", conn, xqc_conn_addr_str(conn)); - } - } - if (conn->conn_state == XQC_CONN_STATE_SERVER_INIT && !(conn->conn_flag & XQC_CONN_FLAG_INIT_RECVD)) { @@ -852,7 +840,7 @@ xqc_int_t xqc_process_ping_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) { xqc_int_t ret; - +#ifdef XQC_PING_ATTACK_PROTECT /* ping frame should not be the first frame in the first initial packet */ if (conn->conn_state == XQC_CONN_STATE_SERVER_INIT && !(conn->conn_flag & XQC_CONN_FLAG_INIT_RECVD)) @@ -861,6 +849,8 @@ xqc_process_ping_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) "|xqc_process_ping_frame error: ping frame shoud not be the first frame|"); return XQC_ERROR; } +#endif + ret = xqc_parse_ping_frame(packet_in, conn); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, diff --git a/src/transport/xqc_packet.c b/src/transport/xqc_packet.c index 543fe52ff..40cac595e 100644 --- a/src/transport/xqc_packet.c +++ b/src/transport/xqc_packet.c @@ -120,6 +120,7 @@ xqc_conn_check_initial_packet_from_cur_state(xqc_conn_state_t cur_state) return XQC_TRUE; } + xqc_int_t xqc_packet_parse_single(xqc_connection_t *c, xqc_packet_in_t *packet_in) { @@ -185,6 +186,12 @@ xqc_packet_parse_single(xqc_connection_t *c, xqc_packet_in_t *packet_in) return ret; } + if (XQC_PTYPE_INIT == XQC_PACKET_LONG_HEADER_GET_TYPE(pos)) { + if (c->conn_type == XQC_CONN_TYPE_SERVER && !(c->conn_flag & XQC_CONN_FLAG_SERVER_ACCEPT)) { + return xqc_conn_server_accept(c); + } + } + } else { xqc_log(c->log, XQC_LOG_INFO, "unknown packet type, first byte[%d], " "skip all buf, skip length: %d", pos[0], packet_in->last - packet_in->pos); diff --git a/src/transport/xqc_packet_out.c b/src/transport/xqc_packet_out.c index f0fe12bfa..b564cc947 100644 --- a/src/transport/xqc_packet_out.c +++ b/src/transport/xqc_packet_out.c @@ -1125,7 +1125,10 @@ xqc_write_new_token_to_packet(xqc_connection_t *conn) unsigned char token[XQC_MAX_TOKEN_LEN]; unsigned token_len = XQC_MAX_TOKEN_LEN; - xqc_conn_gen_token(conn, token, &token_len); + if (xqc_conn_gen_token(conn, token, &token_len) != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|gen token failed|"); + return -XQC_EWRITE_PKT; + } need = 1 /* type */ + xqc_vint_get_2bit(token_len) /* token len */ diff --git a/src/transport/xqc_packet_parser.c b/src/transport/xqc_packet_parser.c index 8d9c11216..d19b51ef6 100644 --- a/src/transport/xqc_packet_parser.c +++ b/src/transport/xqc_packet_parser.c @@ -586,6 +586,12 @@ xqc_packet_encrypt_buf(xqc_connection_t *conn, xqc_packet_out_t *packet_out, size_t enc_payload_len = 0; xqc_encrypt_level_t level = xqc_packet_type_to_enc_level(packet_out->po_pkt.pkt_type); + + /* check encrypt key ready */ + if (xqc_tls_is_key_ready(conn->tls, level, XQC_KEY_TYPE_TX_WRITE) == XQC_FALSE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|crypto not initialized|level:%d|", level); + return -XQC_TLS_INVALID_STATE; + } /* source buffer */ uint8_t *header = (uint8_t *)packet_out->po_buf; @@ -883,6 +889,43 @@ xqc_packet_parse_handshake(xqc_connection_t *c, xqc_packet_in_t *packet_in) return XQC_OK; } +#define RETRY_PSEUDO_PACKET_SIZE (3 * (1 + XQC_MAX_CID_LEN) + 1 + 4 + XQC_MAX_TOKEN_LEN) + +xqc_int_t +xqc_conn_gen_retry_integrity_tag(xqc_connection_t *conn, const uint8_t *odcid_buf, unsigned odcid_len, + uint8_t *retry_buf, unsigned retry_len, uint8_t *tag_buf, size_t *tag_len) +{ + uint8_t pseudo_buf[RETRY_PSEUDO_PACKET_SIZE] = {0}; + size_t pseudo_len = sizeof(uint8_t) + odcid_len + retry_len; + uint8_t *dst_buf = pseudo_buf; + if (retry_len + odcid_len > RETRY_PSEUDO_PACKET_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|xqc_tls_gen_retry_integrity_tag length invalid|retry_len:%d|odcid_len:%d|", + retry_len, odcid_len); + + return XQC_ERROR; + } + + *dst_buf++ = odcid_len; + memcpy(dst_buf, odcid_buf, odcid_len); + dst_buf += odcid_len; + xqc_memcpy(dst_buf, retry_buf, retry_len); + dst_buf += retry_len; + xqc_int_t ret = xqc_tls_cal_retry_integrity_tag(conn->log, + pseudo_buf, pseudo_len, + tag_buf, XQC_RETRY_INTEGRITY_TAG_LEN, + tag_len, conn->version); + + if (ret != XQC_OK || *tag_len != XQC_RETRY_INTEGRITY_TAG_LEN) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|xqc_tls_cal_retry_integrity_tag error|ret:%d|tag_len:%d|", ret, *tag_len); + return XQC_ERROR; + } + + return XQC_OK; +} + + /* * 0 1 2 3 @@ -913,9 +956,9 @@ xqc_packet_parse_handshake(xqc_connection_t *c, xqc_packet_in_t *packet_in) Retry Packet */ -/* TODO: protocol update */ +/* protocol update RFC9000 */ int -xqc_gen_retry_packet(unsigned char *dst_buf, +xqc_gen_retry_packet(xqc_connection_t *conn, unsigned char *dst_buf, const unsigned char *dcid, unsigned char dcid_len, const unsigned char *scid, unsigned char scid_len, const unsigned char *odcid, unsigned char odcid_len, @@ -924,30 +967,37 @@ xqc_gen_retry_packet(unsigned char *dst_buf, { unsigned char *begin = dst_buf; - unsigned char first_byte = 0xC0; first_byte |= XQC_PTYPE_RETRY << 4; - first_byte |= odcid_len - 3; *dst_buf++ = first_byte; ver = htonl(ver); memcpy(dst_buf, &ver, sizeof(ver)); dst_buf += sizeof(ver); - *dst_buf = (dcid_len - 3) << 4; - *dst_buf |= scid_len - 3; - dst_buf++; + *dst_buf++ = dcid_len; memcpy(dst_buf, dcid, dcid_len); dst_buf += dcid_len; + *dst_buf++ = scid_len; memcpy(dst_buf, scid, scid_len); dst_buf += scid_len; - memcpy(dst_buf, odcid, odcid_len); - dst_buf += odcid_len; memcpy(dst_buf, token, token_len); dst_buf += token_len; + + uint8_t retry_integrity_tag[XQC_RETRY_INTEGRITY_TAG_LEN] = {0}; + size_t retry_integrity_tag_len = XQC_RETRY_INTEGRITY_TAG_LEN; + xqc_int_t ret = xqc_conn_gen_retry_integrity_tag(conn, odcid, odcid_len, begin, dst_buf - begin, + retry_integrity_tag, &retry_integrity_tag_len); + + if (ret != XQC_OK) { + return XQC_ERROR; + } + + memcpy(dst_buf, retry_integrity_tag, retry_integrity_tag_len); + dst_buf += retry_integrity_tag_len; return dst_buf - begin; } @@ -972,7 +1022,6 @@ xqc_gen_retry_packet(unsigned char *dst_buf, * Figure 8: Retry Pseudo-Packet */ -#define RETRY_PSEUDO_PACKET_SIZE (3 * (1 + XQC_MAX_CID_LEN) + 1 + 4 + XQC_MAX_TOKEN_LEN) static xqc_int_t xqc_conn_cal_retry_integrity_tag(xqc_connection_t *conn, @@ -982,27 +1031,8 @@ xqc_conn_cal_retry_integrity_tag(xqc_connection_t *conn, uint8_t *retry_buf = (uint8_t *)packet_in->buf; size_t retry_len = packet_in->buf_size - XQC_RETRY_INTEGRITY_TAG_LEN; - uint8_t pseudo_buf[RETRY_PSEUDO_PACKET_SIZE] = {0}; - size_t pseudo_len = sizeof(uint8_t) + odcid->cid_len + retry_len; - - uint8_t *dst_buf = pseudo_buf; - *dst_buf = odcid->cid_len; - dst_buf++; - memcpy(dst_buf, odcid->cid_buf, odcid->cid_len); - dst_buf += odcid->cid_len; - xqc_memcpy(dst_buf, retry_buf, retry_len); - dst_buf += retry_len; - - xqc_int_t ret = xqc_tls_cal_retry_integrity_tag(conn->tls, - pseudo_buf, pseudo_len, - tag_buf, XQC_RETRY_INTEGRITY_TAG_LEN, tag_len); - if (ret != XQC_OK || *tag_len != XQC_RETRY_INTEGRITY_TAG_LEN) { - xqc_log(conn->log, XQC_LOG_ERROR, - "|xqc_tls_cal_retry_integrity_tag error|ret:%d|tag_len:%d|", ret, *tag_len); - return ret; - } - - return XQC_OK; + return xqc_conn_gen_retry_integrity_tag(conn, odcid->cid_buf, odcid->cid_len, retry_buf, + retry_len, tag_buf, tag_len); } diff --git a/src/transport/xqc_packet_parser.h b/src/transport/xqc_packet_parser.h index 056865054..a7deab75e 100644 --- a/src/transport/xqc_packet_parser.h +++ b/src/transport/xqc_packet_parser.h @@ -48,7 +48,7 @@ xqc_int_t xqc_packet_parse_zero_rtt(xqc_connection_t *c, xqc_packet_in_t *packet xqc_int_t xqc_packet_parse_handshake(xqc_connection_t *c, xqc_packet_in_t *packet_in); -int xqc_gen_retry_packet(unsigned char *dst_buf, +int xqc_gen_retry_packet(xqc_connection_t *c, unsigned char *dst_buf, const unsigned char *dcid, unsigned char dcid_len, const unsigned char *scid, unsigned char scid_len, const unsigned char *odcid, unsigned char odcid_len, diff --git a/src/transport/xqc_stream.c b/src/transport/xqc_stream.c index 0477192f2..9eb0dab28 100644 --- a/src/transport/xqc_stream.c +++ b/src/transport/xqc_stream.c @@ -16,7 +16,7 @@ #include "src/transport/xqc_utils.h" #include "src/transport/xqc_pacing.h" #include "src/tls/xqc_tls.h" - +#include "src/transport/xqc_fec.h" static xqc_stream_id_t xqc_gen_stream_id(xqc_connection_t *conn, xqc_stream_type_t type) @@ -705,12 +705,6 @@ xqc_stream_id(xqc_stream_t *stream) return stream->stream_id; } -xqc_usec_t -xqc_update_avg_time(xqc_usec_t new_time, xqc_usec_t ori_time, xqc_int_t ori_time_num) -{ - return (xqc_usec_t)(1.0 * new_time / (ori_time_num + 1) + 1.0 * ori_time / (ori_time_num + 1) * ori_time_num); -} - xqc_bool_t xqc_is_stream_finished(xqc_stream_t *stream) { @@ -742,10 +736,27 @@ xqc_is_stream_finished(xqc_stream_t *stream) } void -xqc_destroy_stream(xqc_stream_t *stream) +xqc_record_stream_state(xqc_stream_t *stream) { - xqc_int_t finished_streams, enable_stream_num, video_frames; + xqc_int_t enable_stream_num, calculated_frames; xqc_usec_t curr_recv_delay, curr_fec_recv_opt; + xqc_usec_t curr_close_delay; + +#define __calc_delay(a, b) ((a && b && (a > b))? (a) - (b) : 0) + calculated_frames = stream->stream_conn->conn_calculated_frames++; + curr_close_delay = __calc_delay(stream->stream_stats.close_time, stream->stream_stats.create_time); + curr_recv_delay = __calc_delay(stream->stream_stats.stream_recv_time, stream->stream_stats.create_time); + stream->stream_conn->conn_avg_close_delay = xqc_update_avg_time(curr_close_delay, stream->stream_conn->conn_avg_close_delay, calculated_frames); + stream->stream_conn->conn_latest_close_delay = curr_close_delay; + stream->stream_conn->conn_avg_recv_delay = xqc_update_avg_time(curr_recv_delay, stream->stream_conn->conn_avg_recv_delay, calculated_frames); + +#undef __calc_delay +} + +void +xqc_destroy_stream(xqc_stream_t *stream) +{ + xqc_int_t finished_streams; #define __calc_delay(a, b) ((a && b && (a > b))? (a) - (b) : 0) @@ -755,26 +766,15 @@ xqc_destroy_stream(xqc_stream_t *stream) if (xqc_is_stream_finished(stream)) { if(stream->stream_conn) { finished_streams = stream->stream_conn->finished_streams++; - if (stream->stream_fec_ctl.is_video_frame) { - video_frames = stream->stream_conn->conn_video_frames++; - xqc_usec_t curr_close_delay; - curr_close_delay = __calc_delay(stream->stream_stats.close_time, stream->stream_stats.create_time); - curr_recv_delay = __calc_delay(stream->stream_stats.stream_recv_time, stream->stream_stats.create_time); - stream->stream_conn->conn_avg_close_delay = xqc_update_avg_time(curr_close_delay, stream->stream_conn->conn_avg_close_delay, video_frames); - stream->stream_conn->conn_latest_close_delay = curr_close_delay; - stream->stream_conn->conn_avg_recv_delay = xqc_update_avg_time(curr_recv_delay, stream->stream_conn->conn_avg_recv_delay, video_frames); - if (stream->stream_conn->fec_ctl) { - if (stream->stream_fec_ctl.enable_fec - || stream->stream_stats.recov_pkt_cnt > 0) - { - enable_stream_num = stream->stream_conn->fec_ctl->fec_enable_stream_num++; - curr_recv_delay = __calc_delay(stream->stream_stats.recv_time_with_fec, stream->stream_stats.create_time); - curr_fec_recv_opt = __calc_delay(stream->stream_stats.final_packet_time, stream->stream_stats.recv_time_with_fec); - stream->stream_conn->fec_ctl->conn_avg_recv_delay = xqc_update_avg_time(curr_recv_delay, stream->stream_conn->fec_ctl->conn_avg_recv_delay, enable_stream_num); - stream->stream_conn->fec_ctl->fec_avg_opt_time = xqc_update_avg_time(curr_fec_recv_opt, stream->stream_conn->fec_ctl->fec_avg_opt_time, enable_stream_num); - } - } +#ifdef XQC_ENABLE_FEC + if (stream->stream_conn->fec_ctl + && ((stream->stream_fec_ctl.enable_fec + || stream->stream_stats.recov_pkt_cnt > 0 + ))) + { + xqc_record_fec_state(stream); } +#endif } } diff --git a/src/transport/xqc_stream.h b/src/transport/xqc_stream.h index 245bae956..449b70247 100644 --- a/src/transport/xqc_stream.h +++ b/src/transport/xqc_stream.h @@ -195,8 +195,6 @@ struct xqc_stream_s { xqc_list_head_t *stream_fec_head; xqc_list_head_t *stream_fec_tail; - uint16_t is_video_frame; - } stream_fec_ctl; }; @@ -296,5 +294,8 @@ void xqc_stream_closing(xqc_stream_t *stream, xqc_int_t err); void xqc_stream_close_discarded_stream(xqc_stream_t *stream); +xqc_bool_t xqc_is_stream_finished(xqc_stream_t *stream); + +void xqc_record_stream_state(xqc_stream_t *stream); #endif /* _XQC_STREAM_H_INCLUDED_ */ diff --git a/tests/test_client.c b/tests/test_client.c index 79de8511c..b2b11ef63 100644 --- a/tests/test_client.c +++ b/tests/test_client.c @@ -17,7 +17,6 @@ #include #include #include "platform.h" - #ifndef XQC_SYS_WINDOWS #include #include @@ -278,6 +277,9 @@ int g_multi_interface_cnt = 0; int mp_has_recved = 0; char g_priority[64] = {'\0'}; +unsigned char g_token[XQC_MAX_TOKEN_LEN]; +int g_token_len = 0; + /* 用于路径增删debug */ int g_debug_path = 0; @@ -291,6 +293,7 @@ int g_periodically_request = 0; static uint64_t last_recv_ts = 0; +static int g_timeout_flag = 0; /* CDF file format: N (N lines) @@ -1139,11 +1142,10 @@ xqc_client_write_socket_ex(uint64_t path_id, if (g_test_case == 46) { /* drop all initial packets to make server buffer 0rtt packets */ header_type = send_buf[0] & 0x80; - /* initial packet */ uint8_t fixed_bit = send_buf[0] & 0x40; xqc_uint_t type = (send_buf[0] & 0x30) >> 4; - if (type == 0) { + if (type == 0 && g_timeout_flag == 0) { //do not drop conn close frame printf("... drop initial pkt, len: %zd\n", size); return size; } @@ -2498,7 +2500,7 @@ xqc_client_request_send(xqc_h3_request_t *h3_request, user_stream_t *user_stream } xqc_http_header_t priority_hdr = { .name = {.iov_base = "priority", .iov_len = 8}, - .value = {.iov_base = g_priority, .iov_len = 63}, + .value = {.iov_base = g_priority, .iov_len = ret}, .flags = 0, }; header[header_size] = priority_hdr; @@ -2513,6 +2515,7 @@ xqc_client_request_send(xqc_h3_request_t *h3_request, user_stream_t *user_stream .schedule = 1, .reinject = 1, .fec = XQC_DEFAULT_SIZE_REQ, + .fastpath = 1, }; xqc_h3_request_set_priority(h3_request, &h3_prio); @@ -2525,7 +2528,7 @@ xqc_client_request_send(xqc_h3_request_t *h3_request, user_stream_t *user_stream xqc_http_header_t priority_hdr = { .name = {.iov_base = "priority", .iov_len = 8}, - .value = {.iov_base = g_priority, .iov_len = 63}, + .value = {.iov_base = g_priority, .iov_len = ret}, .flags = 0, }; header[header_size] = priority_hdr; @@ -3429,6 +3432,7 @@ xqc_client_timeout_callback(int fd, short what, void *arg) printf("[dgram]|echo_check|same_content:%s|\n", !memcmp(user_conn->dgram_blk->data, user_conn->dgram_blk->recv_data, user_conn->dgram_blk->data_len) ? "yes" : "no"); } printf("xqc_client_timeout_callback | conn_close\n"); + g_timeout_flag = 1; rc = xqc_conn_close(ctx.engine, &user_conn->cid); if (rc) { printf("xqc_conn_close error\n"); @@ -3885,6 +3889,10 @@ static void xqc_client_concurrent_callback(int fd, short what, void *arg){ printf("xqc_client_user_conn_multi_process_create error\n"); return; } + if (g_token_len > 0){ + user_conn->token = g_token; + user_conn->token_len = g_token_len; + } xqc_conn_ssl_config_t conn_ssl_config; memset(&conn_ssl_config, 0, sizeof(conn_ssl_config)); @@ -4509,6 +4517,8 @@ int main(int argc, char *argv[]) { xqc_client_open_keylog_file(&ctx); xqc_client_open_log_file(&ctx); + g_token_len = xqc_client_read_token(g_token, XQC_MAX_TOKEN_LEN); + xqc_platform_init_env(); xqc_engine_ssl_config_t engine_ssl_config; @@ -5031,12 +5041,9 @@ int main(int argc, char *argv[]) { conn_settings.scheduler_callback = xqc_backup_fec_scheduler_cb; } - unsigned char token[XQC_MAX_TOKEN_LEN]; - int token_len = XQC_MAX_TOKEN_LEN; - token_len = xqc_client_read_token(token, token_len); - if (token_len > 0) { - user_conn->token = token; - user_conn->token_len = token_len; + if (g_token_len > 0) { + user_conn->token = g_token; + user_conn->token_len = g_token_len; } xqc_conn_ssl_config_t conn_ssl_config; diff --git a/tests/test_server.c b/tests/test_server.c index 3b2d135e2..0665bcbd2 100644 --- a/tests/test_server.c +++ b/tests/test_server.c @@ -2009,6 +2009,13 @@ xqc_keylog_cb(const xqc_cid_t *scid, const char *line, void *user_data) } } +void xqc_server_conn_ssl_msg_cb(int msg_type, + const void *msg, size_t msg_len, void *user_data) +{ + user_conn_t *user_conn = (user_conn_t *)user_data; + printf("user_conn:%p , scid:%s, msg_type:%d, msg_len:%d\n", user_conn, xqc_scid_str(ctx.engine, &user_conn->cid), msg_type, (int)msg_len); +} + #if defined(XQC_SUPPORT_SENDMMSG) && !defined(XQC_SYS_WINDOWS) ssize_t xqc_server_write_mmsg(const struct iovec *msg_iov, unsigned int vlen, const struct sockaddr *peer_addr, @@ -2021,6 +2028,8 @@ ssize_t xqc_server_write_mmsg(const struct iovec *msg_iov, unsigned int vlen, struct mmsghdr mmsg[MAX_SEG]; memset(&mmsg, 0, sizeof(mmsg)); for (int i = 0; i < vlen; i++) { + mmsg[i].msg_hdr.msg_name = (void *)peer_addr; + mmsg[i].msg_hdr.msg_namelen = peer_addrlen; mmsg[i].msg_hdr.msg_iov = (struct iovec *)&msg_iov[i]; mmsg[i].msg_hdr.msg_iovlen = 1; } @@ -2045,6 +2054,19 @@ ssize_t xqc_server_mp_write_mmsg(uint64_t path_id, } #endif +int +xqc_retry_packet_check(xqc_engine_t *engine, xqc_connection_t *conn, const xqc_cid_t *cid, void * user_data) +{ + (void *)engine; + (void *)conn; + (void *)cid; + (void *)user_data; + if (g_test_case == 601) { /* 601 for test retry packet */ + return XQC_TRUE; + } + return XQC_FALSE; +} + void stop(int signo) { @@ -2394,6 +2416,9 @@ int main(int argc, char *argv[]) { .conn_peer_addr_changed_notify = xqc_server_conn_peer_addr_changed_notify, .path_peer_addr_changed_notify = xqc_server_path_peer_addr_changed_notify, .path_removed_notify = xqc_server_path_removed_notify, + .conn_ssl_msg_cb = xqc_server_conn_ssl_msg_cb, + .conn_retry_packet_condition_check = xqc_retry_packet_check, + .conn_send_packet_before_accept = xqc_server_write_socket, }; xqc_cong_ctrl_callback_t cong_ctrl;