diff options
Diffstat (limited to 'src/event/quic/ngx_event_quic_transport.h')
-rw-r--r-- | src/event/quic/ngx_event_quic_transport.h | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/src/event/quic/ngx_event_quic_transport.h b/src/event/quic/ngx_event_quic_transport.h new file mode 100644 index 000000000..16d9095ef --- /dev/null +++ b/src/event/quic/ngx_event_quic_transport.h @@ -0,0 +1,397 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_QUIC_TRANSPORT_H_INCLUDED_ +#define _NGX_EVENT_QUIC_TRANSPORT_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +/* + * RFC 9000, 17.2. Long Header Packets + * 17.3. Short Header Packets + * + * QUIC flags in first byte + */ +#define NGX_QUIC_PKT_LONG 0x80 /* header form */ +#define NGX_QUIC_PKT_FIXED_BIT 0x40 +#define NGX_QUIC_PKT_TYPE 0x30 /* in long packet */ +#define NGX_QUIC_PKT_KPHASE 0x04 /* in short packet */ + +#define ngx_quic_long_pkt(flags) ((flags) & NGX_QUIC_PKT_LONG) +#define ngx_quic_short_pkt(flags) (((flags) & NGX_QUIC_PKT_LONG) == 0) + +/* Long packet types */ +#define NGX_QUIC_PKT_INITIAL 0x00 +#define NGX_QUIC_PKT_ZRTT 0x10 +#define NGX_QUIC_PKT_HANDSHAKE 0x20 +#define NGX_QUIC_PKT_RETRY 0x30 + +#define ngx_quic_pkt_in(flags) \ + (((flags) & NGX_QUIC_PKT_TYPE) == NGX_QUIC_PKT_INITIAL) +#define ngx_quic_pkt_zrtt(flags) \ + (((flags) & NGX_QUIC_PKT_TYPE) == NGX_QUIC_PKT_ZRTT) +#define ngx_quic_pkt_hs(flags) \ + (((flags) & NGX_QUIC_PKT_TYPE) == NGX_QUIC_PKT_HANDSHAKE) +#define ngx_quic_pkt_retry(flags) \ + (((flags) & NGX_QUIC_PKT_TYPE) == NGX_QUIC_PKT_RETRY) + +#define ngx_quic_pkt_rb_mask(flags) \ + (ngx_quic_long_pkt(flags) ? 0x0C : 0x18) +#define ngx_quic_pkt_hp_mask(flags) \ + (ngx_quic_long_pkt(flags) ? 0x0F : 0x1F) + +#define ngx_quic_level_name(lvl) \ + (lvl == ssl_encryption_application) ? "app" \ + : (lvl == ssl_encryption_initial) ? "init" \ + : (lvl == ssl_encryption_handshake) ? "hs" : "early" + +#define NGX_QUIC_MAX_CID_LEN 20 +#define NGX_QUIC_SERVER_CID_LEN NGX_QUIC_MAX_CID_LEN + +/* 12.4. Frames and Frame Types */ +#define NGX_QUIC_FT_PADDING 0x00 +#define NGX_QUIC_FT_PING 0x01 +#define NGX_QUIC_FT_ACK 0x02 +#define NGX_QUIC_FT_ACK_ECN 0x03 +#define NGX_QUIC_FT_RESET_STREAM 0x04 +#define NGX_QUIC_FT_STOP_SENDING 0x05 +#define NGX_QUIC_FT_CRYPTO 0x06 +#define NGX_QUIC_FT_NEW_TOKEN 0x07 +#define NGX_QUIC_FT_STREAM 0x08 +#define NGX_QUIC_FT_STREAM1 0x09 +#define NGX_QUIC_FT_STREAM2 0x0A +#define NGX_QUIC_FT_STREAM3 0x0B +#define NGX_QUIC_FT_STREAM4 0x0C +#define NGX_QUIC_FT_STREAM5 0x0D +#define NGX_QUIC_FT_STREAM6 0x0E +#define NGX_QUIC_FT_STREAM7 0x0F +#define NGX_QUIC_FT_MAX_DATA 0x10 +#define NGX_QUIC_FT_MAX_STREAM_DATA 0x11 +#define NGX_QUIC_FT_MAX_STREAMS 0x12 +#define NGX_QUIC_FT_MAX_STREAMS2 0x13 +#define NGX_QUIC_FT_DATA_BLOCKED 0x14 +#define NGX_QUIC_FT_STREAM_DATA_BLOCKED 0x15 +#define NGX_QUIC_FT_STREAMS_BLOCKED 0x16 +#define NGX_QUIC_FT_STREAMS_BLOCKED2 0x17 +#define NGX_QUIC_FT_NEW_CONNECTION_ID 0x18 +#define NGX_QUIC_FT_RETIRE_CONNECTION_ID 0x19 +#define NGX_QUIC_FT_PATH_CHALLENGE 0x1A +#define NGX_QUIC_FT_PATH_RESPONSE 0x1B +#define NGX_QUIC_FT_CONNECTION_CLOSE 0x1C +#define NGX_QUIC_FT_CONNECTION_CLOSE_APP 0x1D +#define NGX_QUIC_FT_HANDSHAKE_DONE 0x1E + +#define NGX_QUIC_FT_LAST NGX_QUIC_FT_HANDSHAKE_DONE + +/* 22.5. QUIC Transport Error Codes Registry */ +#define NGX_QUIC_ERR_NO_ERROR 0x00 +#define NGX_QUIC_ERR_INTERNAL_ERROR 0x01 +#define NGX_QUIC_ERR_CONNECTION_REFUSED 0x02 +#define NGX_QUIC_ERR_FLOW_CONTROL_ERROR 0x03 +#define NGX_QUIC_ERR_STREAM_LIMIT_ERROR 0x04 +#define NGX_QUIC_ERR_STREAM_STATE_ERROR 0x05 +#define NGX_QUIC_ERR_FINAL_SIZE_ERROR 0x06 +#define NGX_QUIC_ERR_FRAME_ENCODING_ERROR 0x07 +#define NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR 0x08 +#define NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR 0x09 +#define NGX_QUIC_ERR_PROTOCOL_VIOLATION 0x0A +#define NGX_QUIC_ERR_INVALID_TOKEN 0x0B +#define NGX_QUIC_ERR_APPLICATION_ERROR 0x0C +#define NGX_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED 0x0D +#define NGX_QUIC_ERR_KEY_UPDATE_ERROR 0x0E +#define NGX_QUIC_ERR_AEAD_LIMIT_REACHED 0x0F +#define NGX_QUIC_ERR_NO_VIABLE_PATH 0x10 + +#define NGX_QUIC_ERR_CRYPTO_ERROR 0x100 + +#define NGX_QUIC_ERR_CRYPTO(e) (NGX_QUIC_ERR_CRYPTO_ERROR + (e)) + + +/* 22.3. QUIC Transport Parameters Registry */ +#define NGX_QUIC_TP_ORIGINAL_DCID 0x00 +#define NGX_QUIC_TP_MAX_IDLE_TIMEOUT 0x01 +#define NGX_QUIC_TP_SR_TOKEN 0x02 +#define NGX_QUIC_TP_MAX_UDP_PAYLOAD_SIZE 0x03 +#define NGX_QUIC_TP_INITIAL_MAX_DATA 0x04 +#define NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL 0x05 +#define NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE 0x06 +#define NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI 0x07 +#define NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI 0x08 +#define NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI 0x09 +#define NGX_QUIC_TP_ACK_DELAY_EXPONENT 0x0A +#define NGX_QUIC_TP_MAX_ACK_DELAY 0x0B +#define NGX_QUIC_TP_DISABLE_ACTIVE_MIGRATION 0x0C +#define NGX_QUIC_TP_PREFERRED_ADDRESS 0x0D +#define NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT 0x0E +#define NGX_QUIC_TP_INITIAL_SCID 0x0F +#define NGX_QUIC_TP_RETRY_SCID 0x10 + +#define NGX_QUIC_CID_LEN_MIN 8 +#define NGX_QUIC_CID_LEN_MAX 20 + +#define NGX_QUIC_MAX_RANGES 10 + + +typedef struct { + uint64_t gap; + uint64_t range; +} ngx_quic_ack_range_t; + + +typedef struct { + uint64_t largest; + uint64_t delay; + uint64_t range_count; + uint64_t first_range; + uint64_t ect0; + uint64_t ect1; + uint64_t ce; + uint64_t ranges_length; +} ngx_quic_ack_frame_t; + + +typedef struct { + uint64_t seqnum; + uint64_t retire; + uint8_t len; + u_char cid[NGX_QUIC_CID_LEN_MAX]; + u_char srt[NGX_QUIC_SR_TOKEN_LEN]; +} ngx_quic_new_conn_id_frame_t; + + +typedef struct { + uint64_t length; +} ngx_quic_new_token_frame_t; + +/* + * common layout for CRYPTO and STREAM frames; + * conceptually, CRYPTO frame is also a stream + * frame lacking some properties + */ +typedef struct { + uint64_t offset; + uint64_t length; +} ngx_quic_ordered_frame_t; + +typedef ngx_quic_ordered_frame_t ngx_quic_crypto_frame_t; + + +typedef struct { + /* initial fields same as in ngx_quic_ordered_frame_t */ + uint64_t offset; + uint64_t length; + + uint64_t stream_id; + unsigned off:1; + unsigned len:1; + unsigned fin:1; +} ngx_quic_stream_frame_t; + + +typedef struct { + uint64_t max_data; +} ngx_quic_max_data_frame_t; + + +typedef struct { + uint64_t error_code; + uint64_t frame_type; + ngx_str_t reason; +} ngx_quic_close_frame_t; + + +typedef struct { + uint64_t id; + uint64_t error_code; + uint64_t final_size; +} ngx_quic_reset_stream_frame_t; + + +typedef struct { + uint64_t id; + uint64_t error_code; +} ngx_quic_stop_sending_frame_t; + + +typedef struct { + uint64_t limit; + ngx_uint_t bidi; /* unsigned: bidi:1 */ +} ngx_quic_streams_blocked_frame_t; + + +typedef struct { + uint64_t limit; + ngx_uint_t bidi; /* unsigned: bidi:1 */ +} ngx_quic_max_streams_frame_t; + + +typedef struct { + uint64_t id; + uint64_t limit; +} ngx_quic_max_stream_data_frame_t; + + +typedef struct { + uint64_t limit; +} ngx_quic_data_blocked_frame_t; + + +typedef struct { + uint64_t id; + uint64_t limit; +} ngx_quic_stream_data_blocked_frame_t; + + +typedef struct { + uint64_t sequence_number; +} ngx_quic_retire_cid_frame_t; + + +typedef struct { + u_char data[8]; +} ngx_quic_path_challenge_frame_t; + + +typedef struct ngx_quic_frame_s ngx_quic_frame_t; + +struct ngx_quic_frame_s { + ngx_uint_t type; + enum ssl_encryption_level_t level; + ngx_queue_t queue; + uint64_t pnum; + size_t plen; + ngx_msec_t first; + ngx_msec_t last; + ssize_t len; + unsigned need_ack:1; + unsigned pkt_need_ack:1; + unsigned flush:1; + + ngx_chain_t *data; + union { + ngx_quic_ack_frame_t ack; + ngx_quic_crypto_frame_t crypto; + ngx_quic_ordered_frame_t ord; + ngx_quic_new_conn_id_frame_t ncid; + ngx_quic_new_token_frame_t token; + ngx_quic_stream_frame_t stream; + ngx_quic_max_data_frame_t max_data; + ngx_quic_close_frame_t close; + ngx_quic_reset_stream_frame_t reset_stream; + ngx_quic_stop_sending_frame_t stop_sending; + ngx_quic_streams_blocked_frame_t streams_blocked; + ngx_quic_max_streams_frame_t max_streams; + ngx_quic_max_stream_data_frame_t max_stream_data; + ngx_quic_data_blocked_frame_t data_blocked; + ngx_quic_stream_data_blocked_frame_t stream_data_blocked; + ngx_quic_retire_cid_frame_t retire_cid; + ngx_quic_path_challenge_frame_t path_challenge; + ngx_quic_path_challenge_frame_t path_response; + } u; +}; + + +typedef struct { + ngx_log_t *log; + ngx_quic_path_t *path; + + ngx_quic_keys_t *keys; + + ngx_msec_t received; + uint64_t number; + uint8_t num_len; + uint32_t trunc; + uint8_t flags; + uint32_t version; + ngx_str_t token; + enum ssl_encryption_level_t level; + ngx_uint_t error; + + /* filled in by parser */ + ngx_buf_t *raw; /* udp datagram */ + + u_char *data; /* quic packet */ + size_t len; + + /* cleartext fields */ + ngx_str_t odcid; /* retry packet tag */ + u_char odcid_buf[NGX_QUIC_MAX_CID_LEN]; + ngx_str_t dcid; + ngx_str_t scid; + uint64_t pn; + u_char *plaintext; + ngx_str_t payload; /* decrypted data */ + + unsigned need_ack:1; + unsigned key_phase:1; + unsigned key_update:1; + unsigned parsed:1; + unsigned decrypted:1; + unsigned validated:1; + unsigned retried:1; + unsigned first:1; + unsigned rebound:1; +} ngx_quic_header_t; + + +typedef struct { + ngx_msec_t max_idle_timeout; + ngx_msec_t max_ack_delay; + + size_t max_udp_payload_size; + size_t initial_max_data; + size_t initial_max_stream_data_bidi_local; + size_t initial_max_stream_data_bidi_remote; + size_t initial_max_stream_data_uni; + ngx_uint_t initial_max_streams_bidi; + ngx_uint_t initial_max_streams_uni; + ngx_uint_t ack_delay_exponent; + ngx_uint_t active_connection_id_limit; + ngx_flag_t disable_active_migration; + + ngx_str_t original_dcid; + ngx_str_t initial_scid; + ngx_str_t retry_scid; + u_char sr_token[NGX_QUIC_SR_TOKEN_LEN]; + + /* TODO */ + void *preferred_address; +} ngx_quic_tp_t; + + +ngx_int_t ngx_quic_parse_packet(ngx_quic_header_t *pkt); + +size_t ngx_quic_create_version_negotiation(ngx_quic_header_t *pkt, u_char *out); + +size_t ngx_quic_payload_size(ngx_quic_header_t *pkt, size_t pkt_len); + +size_t ngx_quic_create_header(ngx_quic_header_t *pkt, u_char *out, + u_char **pnp); + +size_t ngx_quic_create_retry_itag(ngx_quic_header_t *pkt, u_char *out, + u_char **start); + +ssize_t ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end, + ngx_quic_frame_t *frame); +ssize_t ngx_quic_create_frame(u_char *p, ngx_quic_frame_t *f); + +ssize_t ngx_quic_parse_ack_range(ngx_log_t *log, u_char *start, + u_char *end, uint64_t *gap, uint64_t *range); +size_t ngx_quic_create_ack_range(u_char *p, uint64_t gap, uint64_t range); + +ngx_int_t ngx_quic_init_transport_params(ngx_quic_tp_t *tp, + ngx_quic_conf_t *qcf); +ngx_int_t ngx_quic_parse_transport_params(u_char *p, u_char *end, + ngx_quic_tp_t *tp, ngx_log_t *log); +ssize_t ngx_quic_create_transport_params(u_char *p, u_char *end, + ngx_quic_tp_t *tp, size_t *clen); + +void ngx_quic_dcid_encode_key(u_char *dcid, uint64_t key); + +#endif /* _NGX_EVENT_QUIC_TRANSPORT_H_INCLUDED_ */ |