RFC 9000 QUIC 전송 프로토콜 2021년 5월
Iyengar & Thomson 표준 트랙 [페이지]
스트림:
인터넷 엔지니어링 태스크 포스(IETF)
RFC:
9000
범주:
표준 트랙
게시:
ISSN:
2070-1721
저자:
J. Iyengar, 편집자
Fastly
M. Thomson, 편집자
Mozilla

RFC 9000

QUIC: UDP 기반 다중화 및 보안 전송

초록

이 문서는 QUIC 전송 프로토콜의 핵심을 정의한다. QUIC는 애플리케이션에 구조화된 통신을 위한 흐름 제어 스트림, 저지연 연결 설정 및 네트워크 경로 마이그레이션을 제공한다. QUIC에는 다양한 배포 환경에서 기밀성, 무결성 및 가용성을 보장하는 보안 조치가 포함된다. 동반 문서에서는 키 협상을 위한 TLS의 통합, 손실 감지 및 예시적인 혼잡 제어 알고리즘을 설명한다.

이 메모의 상태

이것은 인터넷 표준 트랙 문서이다.

이 문서는 인터넷 엔지니어링 태스크 포스 (IETF)의 산출물이다. 이는 IETF 커뮤니티의 합의를 나타낸다. 이 문서는 공개 검토를 받았으며 인터넷 엔지니어링 운영 그룹(IESG)에 의해 게시 승인을 받았다. 인터넷 표준에 관한 추가 정보는 RFC 7841의 Section 2에서 확인할 수 있다.

이 문서의 현재 상태, 모든 정오표 및 이에 대한 피드백 제공 방법에 관한 정보는 https://www.rfc-editor.org/info/rfc9000에서 얻을 수 있다.

목차

1. 개요

QUIC는 안전한 범용 전송 프로토콜이다. 이 문서는 QUIC의 버전 1을 정의하며, [QUIC-INVARIANTS]에 정의된 QUIC의 버전 독립적 속성을 따른다.

QUIC는 클라이언트와 서버 사이에 상태를 가지는 상호작용을 생성하는 연결 지향 프로토콜이다.

QUIC 핸드셰이크는 암호화 및 전송 매개변수의 협상을 결합한다. QUIC는 TLS 핸드셰이크 [TLS13]를 통합하지만, 패킷을 보호하기 위해 맞춤형 프레이밍을 사용한다. TLS와 QUIC의 통합은 [QUIC-TLS]에서 더 자세히 설명한다. 핸드셰이크는 가능한 한 빨리 애플리케이션 데이터의 교환을 허용하도록 구성된다. 여기에는 클라이언트가 데이터를 즉시 보낼 수 있는 옵션(0-RTT)이 포함되며, 이를 활성화하려면 어떤 형태의 사전 통신이나 구성이 필요하다.

엔드포인트는 QUIC 패킷을 교환하여 QUIC에서 통신한다. 대부분의 패킷에는 프레임이 포함되며, 프레임은 엔드포인트 사이에서 제어 정보와 애플리케이션 데이터를 운반한다. QUIC는 각 패킷 전체를 인증하고 각 패킷에서 실용적인 만큼 많은 부분을 암호화한다. QUIC 패킷은 기존 시스템과 네트워크에서 배포를 더 쉽게 하기 위해 UDP 데이터그램 [UDP]으로 운반된다.

애플리케이션 프로토콜은 QUIC 연결을 통해 스트림을 사용해 정보를 교환하며, 스트림은 정렬된 바이트 시퀀스이다. 두 가지 유형의 스트림을 생성할 수 있다: 양방향 스트림은 두 엔드포인트가 모두 데이터를 보낼 수 있게 하며, 단방향 스트림은 하나의 엔드포인트만 데이터를 보낼 수 있게 한다. 스트림 생성을 제한하고 전송할 수 있는 데이터 양을 한정하기 위해 크레딧 기반 방식이 사용된다.

QUIC는 신뢰성 있는 전달과 혼잡 제어를 구현하는 데 필요한 피드백을 제공한다. 데이터 손실을 감지하고 복구하기 위한 알고리즘은 Section 6 of [QUIC-RECOVERY]에 설명되어 있다. QUIC는 네트워크 혼잡을 피하기 위해 혼잡 제어에 의존한다. 예시적인 혼잡 제어 알고리즘은 Section 7 of [QUIC-RECOVERY]에 설명되어 있다.

QUIC 연결은 단일 네트워크 경로에 엄격하게 묶이지 않는다. 연결 마이그레이션은 연결 식별자를 사용하여 연결이 새로운 네트워크 경로로 전환될 수 있게 한다. 이 버전의 QUIC에서는 클라이언트만 마이그레이션할 수 있다. 이 설계는 또한 NAT 리바인딩으로 인해 발생할 수 있는 네트워크 토폴로지나 주소 매핑 변경 이후에도 연결이 계속될 수 있게 한다.

일단 설정되면, 연결 종료를 위한 여러 옵션이 제공된다. 애플리케이션은 정상적인 종료를 관리할 수 있고, 엔드포인트는 타임아웃 기간을 협상할 수 있으며, 오류는 즉시 연결 해제를 일으킬 수 있고, 상태 없는 메커니즘은 한 엔드포인트가 상태를 잃은 후 연결을 종료할 수 있게 한다.

1.1. 문서 구조

이 문서는 핵심 QUIC 프로토콜을 설명하며 다음과 같이 구성된다:

  • 스트림은 QUIC가 제공하는 기본 서비스 추상화이다.

    • Section 2는 스트림과 관련된 핵심 개념을 설명하고,
    • Section 3는 스트림 상태를 위한 참조 모델을 제공하며,
    • Section 4는 흐름 제어의 동작을 개괄한다.
  • 연결은 QUIC 엔드포인트가 통신하는 컨텍스트이다.

    • Section 5는 연결과 관련된 핵심 개념을 설명하고,
    • Section 6는 버전 협상을 설명하며,
    • Section 7은 연결 설정 프로세스를 자세히 설명하고,
    • Section 8은 주소 검증과 중요한 서비스 거부 완화책을 설명하며,
    • Section 9는 엔드포인트가 연결을 새로운 네트워크 경로로 마이그레이션하는 방법을 설명하고,
    • Section 10은 열린 연결을 종료하기 위한 옵션을 나열하며,
    • Section 11은 스트림 및 연결 오류 처리를 위한 지침을 제공한다.
  • 패킷과 프레임은 QUIC가 통신하는 데 사용하는 기본 단위이다.

    • Section 12는 패킷 및 프레임과 관련된 개념을 설명하고,
    • Section 13은 데이터의 전송, 재전송 및 확인 응답에 대한 모델을 정의하며,
    • Section 14는 QUIC 패킷을 운반하는 데이터그램 크기를 관리하기 위한 규칙을 지정한다.
  • 마지막으로, QUIC 프로토콜 요소의 인코딩 세부사항은 다음에 설명되어 있다:

동반 문서들은 QUIC의 손실 감지 및 혼잡 제어 [QUIC-RECOVERY], 그리고 TLS 및 기타 암호화 메커니즘의 사용 [QUIC-TLS]을 설명한다.

이 문서는 QUIC 버전 1을 정의하며, 이는 [QUIC-INVARIANTS]의 프로토콜 불변사항을 따른다.

QUIC 버전 1을 참조하려면 이 문서를 인용한다. QUIC의 제한된 버전 독립적 속성 집합에 대한 참조는 [QUIC-INVARIANTS]를 인용할 수 있다.

1.2. 용어 및 정의

이 문서의 핵심 단어 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", 및 "OPTIONAL"은 여기에 표시된 것처럼 모두 대문자로 나타날 때에만 BCP 14 [RFC2119] [RFC8174]에 설명된 대로 해석되어야 한다.

이 문서에서 일반적으로 사용되는 용어는 아래에 설명되어 있다.

QUIC:

이 문서에서 설명하는 전송 프로토콜. QUIC는 이름이며, 약어가 아니다.

엔드포인트:

QUIC 패킷을 생성, 수신 및 처리함으로써 QUIC 연결에 참여할 수 있는 엔티티. QUIC에는 클라이언트와 서버라는 두 가지 유형의 엔드포인트만 있다.

클라이언트:

QUIC 연결을 시작하는 엔드포인트.

서버:

QUIC 연결을 수락하는 엔드포인트.

QUIC 패킷:

UDP 데이터그램에 캡슐화될 수 있는 QUIC의 완전한 처리 가능 단위. 하나 이상의 QUIC 패킷이 단일 UDP 데이터그램에 캡슐화될 수 있다.

Ack-eliciting 패킷:

ACK, PADDING 및 CONNECTION_CLOSE 이외의 프레임을 포함하는 QUIC 패킷. 이는 수신자가 확인 응답을 보내게 한다. Section 13.2.1을 참조한다.

프레임:

구조화된 프로토콜 정보의 단위. 여러 프레임 유형이 있으며, 각각은 서로 다른 정보를 운반한다. 프레임은 QUIC 패킷에 포함된다.

주소:

한정 없이 사용될 때, 네트워크 경로의 한쪽 끝을 나타내는 IP 버전, IP 주소 및 UDP 포트 번호의 튜플.

연결 ID:

엔드포인트에서 QUIC 연결을 식별하는 데 사용되는 식별자. 각 엔드포인트는 피어가 해당 엔드포인트로 보내는 패킷에 포함할 하나 이상의 연결 ID를 선택한다. 이 값은 피어에게 불투명하다.

스트림:

QUIC 연결 내부의 정렬된 바이트로 이루어진 단방향 또는 양방향 채널. QUIC 연결은 여러 동시 스트림을 운반할 수 있다.

애플리케이션:

QUIC를 사용해 데이터를 보내고 받는 엔티티.

이 문서는 각 프로토콜의 단위를 가리키기 위해 "QUIC packets", "UDP datagrams", 그리고 "IP packets"라는 용어를 사용한다. 즉, 하나 이상의 QUIC 패킷이 UDP 데이터그램에 캡슐화될 수 있고, 이는 다시 IP 패킷에 캡슐화된다.

1.3. 표기 규칙

이 문서의 패킷 및 프레임 다이어그램은 맞춤형 형식을 사용한다. 이 형식의 목적은 프로토콜 요소를 정의하는 것이 아니라 요약하는 것이다. 산문은 구조의 완전한 의미와 세부사항을 정의한다.

복합 필드는 이름이 지정된 뒤 한 쌍의 일치하는 중괄호로 둘러싸인 필드 목록이 뒤따른다. 이 목록의 각 필드는 쉼표로 구분된다.

개별 필드에는 길이 정보와 함께 고정 값, 선택성 또는 반복에 대한 표시가 포함된다. 개별 필드는 다음 표기 규칙을 사용하며, 모든 길이는 비트 단위이다:

x (A):

x가 A비트 길이임을 나타낸다

x (i):

x가 Section 16에 설명된 가변 길이 인코딩을 사용하여 정수 값을 보유함을 나타낸다

x (A..B):

x가 A부터 B까지 임의의 길이를 가질 수 있음을 나타낸다. A를 생략하면 최소값이 0비트임을 나타내고, B를 생략하면 설정된 상한이 없음을 나타낸다; 이 형식의 값은 항상 바이트 경계에서 끝난다

x (L) = C:

x가 고정 값 C를 가짐을 나타낸다; x의 길이는 L로 설명되며, 이는 위의 길이 형식 중 어느 것이든 사용할 수 있다

x (L) = C..D:

x가 C부터 D까지의 범위에 있는 값을 가짐을 나타내며, 양끝값을 포함하고, 길이는 위와 같이 L로 설명된다

[x (L)]:

x가 선택 사항이며 길이가 L임을 나타낸다

x (L) ...:

x가 0회 이상 반복되며 각 인스턴스의 길이가 L임을 나타낸다

이 문서는 네트워크 바이트 순서(즉, 빅 엔디언) 값을 사용한다. 필드는 각 바이트의 상위 비트부터 배치된다.

관례상, 개별 필드는 복합 필드의 이름을 사용하여 복합 필드를 참조한다.

Figure 1은 예를 제공한다:

Example Structure {
  One-bit Field (1),
  7-bit Field with Fixed Value (7) = 61,
  Field with Variable-Length Integer (i),
  Arbitrary-Length Field (..),
  Variable-Length Field (8..24),
  Field With Minimum Length (16..),
  Field With Maximum Length (..128),
  [Optional Field (64)],
  Repeated Field (8) ...,
}
Figure 1: 예시 형식

산문에서 단일 비트 필드를 참조할 때, 그 필드의 위치는 해당 필드의 값이 설정된 상태에서 그 필드를 담고 있는 바이트의 값을 사용해 명확히 할 수 있다. 예를 들어, Figure 1의 One-bit Field처럼 바이트의 최상위 비트에 있는 단일 비트 필드를 가리키기 위해 값 0x80을 사용할 수 있다.

2. 스트림

QUIC의 스트림은 애플리케이션에 경량의 정렬된 바이트 스트림 추상화를 제공한다. 스트림은 단방향 또는 양방향일 수 있다.

스트림은 데이터를 전송함으로써 생성될 수 있다. 스트림 관리와 관련된 다른 프로세스 -- 종료, 취소 및 흐름 제어 관리 -- 는 모두 최소한의 오버헤드를 부과하도록 설계되어 있다. 예를 들어, 단일 STREAM 프레임 (Section 19.8)은 스트림을 열고, 그 스트림에 대한 데이터를 운반하고, 스트림을 닫을 수 있다. 스트림은 또한 장기적으로 유지될 수 있으며 연결의 전체 지속 시간 동안 계속될 수 있다.

스트림은 어느 엔드포인트에서든 생성될 수 있고, 다른 스트림과 교차되며 동시에 데이터를 보낼 수 있고, 취소될 수 있다. QUIC는 서로 다른 스트림의 바이트 사이에서 순서를 보장하는 어떤 수단도 제공하지 않는다.

QUIC는 흐름 제어 제약과 스트림 제한에 따라, 임의 개수의 스트림이 동시에 동작하고 임의 양의 데이터가 어떤 스트림에서도 전송될 수 있게 한다. Section 4를 참조한다.

2.1. 스트림 유형 및 식별자

스트림은 단방향 또는 양방향일 수 있다. 단방향 스트림은 한 방향으로 데이터를 운반한다: 스트림의 개시자에서 그 피어로. 양방향 스트림은 양방향으로 데이터를 보낼 수 있게 한다.

스트림은 연결 내부에서 스트림 ID라고 부르는 숫자 값으로 식별된다. 스트림 ID는 62비트 정수(0부터 262-1)이며, 연결의 모든 스트림에 대해 고유하다. 스트림 ID는 가변 길이 정수로 인코딩된다. Section 16을 참조한다. QUIC 엔드포인트는 연결 내부에서 스트림 ID를 재사용해서는 MUST NOT 된다.

스트림 ID의 최하위 비트(0x01)는 스트림의 개시자를 식별한다. 클라이언트가 개시한 스트림은 짝수 번호의 스트림 ID(해당 비트가 0으로 설정됨)를 가지며, 서버가 개시한 스트림은 홀수 번호의 스트림 ID(해당 비트가 1로 설정됨)를 가진다.

스트림 ID의 두 번째 최하위 비트(0x02)는 양방향 스트림(해당 비트가 0으로 설정됨)과 단방향 스트림(해당 비트가 1로 설정됨)을 구분한다.

따라서 스트림 ID의 두 최하위 비트는 Table 1에 요약된 것처럼 스트림을 네 가지 유형 중 하나로 식별한다.

Table 1: 스트림 ID 유형
비트 스트림 유형
0x00 클라이언트 개시, 양방향
0x01 서버 개시, 양방향
0x02 클라이언트 개시, 단방향
0x03 서버 개시, 단방향

각 유형의 스트림 공간은 각각 최소값(0x00부터 0x03까지)에서 시작한다; 각 유형의 후속 스트림은 숫자가 증가하는 스트림 ID로 생성된다. 순서를 벗어나 사용된 스트림 ID는 해당 유형에서 더 낮은 번호의 스트림 ID를 가진 모든 스트림도 열린 것으로 만든다.

2.2. 데이터 송수신

STREAM 프레임(Section 19.8)은 애플리케이션이 보낸 데이터를 캡슐화한다. 엔드포인트는 STREAM 프레임의 Stream ID 및 Offset 필드를 사용하여 데이터를 순서대로 배치한다.

엔드포인트는 스트림 데이터를 정렬된 바이트 스트림으로 애플리케이션에 전달할 수 있어야 MUST 한다. 정렬된 바이트 스트림을 전달하려면 엔드포인트가 광고된 흐름 제어 한도까지 순서가 어긋나 수신된 모든 데이터를 버퍼링해야 한다.

QUIC는 스트림 데이터를 순서 없이 전달하는 데 대해 특별한 허용을 하지 않는다. 그러나 구현은 수신 애플리케이션에 데이터를 순서 없이 전달하는 기능을 제공하기로 선택할 수 MAY 있다.

엔드포인트는 같은 스트림 오프셋에서 여러 번 데이터를 수신할 수 있다. 이미 수신된 데이터는 버릴 수 있다. 주어진 오프셋의 데이터는 여러 번 전송되더라도 변경되어서는 MUST NOT 안 된다; 엔드포인트는 스트림 내 같은 오프셋에서 서로 다른 데이터를 수신하는 것을 PROTOCOL_VIOLATION 유형의 연결 오류로 처리할 수 MAY 있다.

스트림은 QUIC에 보이는 다른 구조가 없는 정렬된 바이트 스트림 추상화이다. STREAM 프레임 경계는 데이터가 전송되거나, 패킷 손실 후 재전송되거나, 수신자에서 애플리케이션에 전달될 때 보존될 것으로 기대되지 않는다.

엔드포인트는 피어가 설정한 흐름 제어 한도 내에 있음을 보장하지 않고서는 어떤 스트림에서도 데이터를 보내서는 MUST NOT 안 된다. 흐름 제어는 Section 4에서 자세히 설명한다.

2.3. 스트림 우선순위 지정

스트림 다중화는 스트림에 할당된 리소스가 올바르게 우선순위화된다면 애플리케이션 성능에 상당한 영향을 줄 수 있다.

QUIC는 우선순위 지정 정보를 교환하기 위한 메커니즘을 제공하지 않는다. 대신 애플리케이션으로부터 우선순위 정보를 받는 데 의존한다.

QUIC 구현은 애플리케이션이 스트림의 상대적 우선순위를 나타낼 수 있는 방법을 제공해야 SHOULD 한다. 구현은 애플리케이션이 제공한 정보를 사용하여 활성 스트림에 리소스를 어떻게 할당할지 결정한다.

2.4. 스트림에 대한 작업

이 문서는 QUIC용 API를 정의하지 않는다; 대신 애플리케이션 프로토콜이 의존할 수 있는 스트림에 대한 기능 집합을 정의한다. 애플리케이션 프로토콜은 QUIC 구현이 이 섹션에서 설명한 작업을 포함하는 인터페이스를 제공한다고 가정할 수 있다. 특정 애플리케이션 프로토콜과 함께 사용하도록 설계된 구현은 그 프로토콜에서 사용되는 작업만 제공할 수도 있다.

스트림의 송신 부분에서 애플리케이션 프로토콜은 다음을 수행할 수 있다:

  • 쓰기 데이터에 대한 스트림 흐름 제어 크레딧 (Section 4.1)이 성공적으로 예약되어 전송될 수 있음을 이해하면서 데이터를 쓸 수 있다;
  • 스트림을 종료할 수 있다(정상 종료). 이는 FIN 비트가 설정된 STREAM 프레임 (Section 19.8)을 발생시킨다; 그리고
  • 스트림을 재설정할 수 있다(갑작스러운 종료). 이는 스트림이 이미 종료 상태가 아닌 경우 RESET_STREAM 프레임 (Section 19.4)을 발생시킨다.

스트림의 수신 부분에서 애플리케이션 프로토콜은 다음을 수행할 수 있다:

  • 데이터를 읽을 수 있다; 그리고
  • 스트림 읽기를 중단하고 닫기를 요청할 수 있으며, 이는 STOP_SENDING 프레임(Section 19.5)을 발생시킬 수 있다.

애플리케이션 프로토콜은 또한 피어가 스트림을 열거나 재설정했을 때, 피어가 스트림 읽기를 중단했을 때, 새 데이터를 사용할 수 있을 때, 그리고 흐름 제어로 인해 스트림에 데이터를 쓸 수 있거나 쓸 수 없을 때를 포함하여 스트림의 상태 변경을 알리도록 요청할 수 있다.

3. 스트림 상태

이 섹션은 스트림을 송신 또는 수신 구성요소의 관점에서 설명한다. 두 개의 상태 기계를 설명한다. 하나는 엔드포인트가 데이터를 전송하는 스트림에 대한 것(Section 3.1)이고, 다른 하나는 엔드포인트가 데이터를 수신하는 스트림에 대한 것(Section 3.2)이다.

단방향 스트림은 스트림 유형과 엔드포인트 역할에 따라 송신 또는 수신 상태 기계 중 하나를 사용한다. 양방향 스트림은 두 엔드포인트 모두에서 두 상태 기계를 모두 사용한다. 대부분의 경우 이러한 상태 기계의 사용 방식은 스트림이 단방향인지 양방향인지와 관계없이 동일하다. 양방향 스트림에서는 송신 측 또는 수신 측 중 어느 하나가 열리면 스트림이 양방향으로 열리기 때문에, 스트림을 여는 조건이 약간 더 복잡하다.

이 섹션에 표시된 상태 기계는 대체로 정보 제공용이다. 이 문서는 스트림 상태를 사용하여 서로 다른 유형의 프레임을 언제 어떻게 보낼 수 있는지에 대한 규칙과, 서로 다른 유형의 프레임을 수신했을 때 예상되는 반응을 설명한다. 이러한 상태 기계는 QUIC 구현에 유용하도록 의도되었지만, 이러한 상태가 구현을 제약하도록 의도된 것은 아니다. 구현은 이러한 상태를 구현한 구현과 동작이 일치하는 한 다른 상태 기계를 정의할 수 있다.

3.1. 송신 스트림 상태

Figure 2는 피어에게 데이터를 보내는 스트림 부분의 상태를 보여준다.

       o
       | Create Stream (Sending)
       | Peer Creates Bidirectional Stream
       v
   +-------+
   | Ready | Send RESET_STREAM
   |       |-----------------------.
   +-------+                       |
       |                           |
       | Send STREAM /             |
       |      STREAM_DATA_BLOCKED  |
       v                           |
   +-------+                       |
   | Send  | Send RESET_STREAM     |
   |       |---------------------->|
   +-------+                       |
       |                           |
       | Send STREAM + FIN         |
       v                           v
   +-------+                   +-------+
   | Data  | Send RESET_STREAM | Reset |
   | Sent  |------------------>| Sent  |
   +-------+                   +-------+
       |                           |
       | Recv All ACKs             | Recv ACK
       v                           v
   +-------+                   +-------+
   | Data  |                   | Reset |
   | Recvd |                   | Recvd |
   +-------+                   +-------+
Figure 2: 스트림의 송신 부분에 대한 상태

엔드포인트가 개시한 스트림의 송신 부분(클라이언트의 경우 유형 0 및 2, 서버의 경우 1 및 3)은 애플리케이션에 의해 열린다. "Ready" 상태는 애플리케이션으로부터 데이터를 받을 수 있는 새로 생성된 스트림을 나타낸다. 이 상태에서는 전송 준비를 위해 스트림 데이터가 버퍼링될 수 있다.

첫 번째 STREAM 또는 STREAM_DATA_BLOCKED 프레임을 보내면 스트림의 송신 부분이 "Send" 상태로 들어간다. 구현은 첫 번째 STREAM 프레임을 보내고 이 상태로 들어갈 때까지 스트림 ID를 스트림에 할당하는 것을 지연하기로 선택할 수 있으며, 이는 더 나은 스트림 우선순위 지정을 가능하게 할 수 있다.

피어가 개시한 양방향 스트림의 송신 부분(서버의 경우 유형 0, 클라이언트의 경우 유형 1)은 수신 부분이 생성될 때 "Ready" 상태에서 시작한다.

"Send" 상태에서 엔드포인트는 STREAM 프레임으로 스트림 데이터를 전송하며, 필요에 따라 재전송한다. 엔드포인트는 피어가 설정한 흐름 제어 한도를 준수하고 MAX_STREAM_DATA 프레임을 계속 수락하고 처리한다. "Send" 상태의 엔드포인트는 스트림 흐름 제어 한도(Section 4.1)로 인해 전송이 차단되면 STREAM_DATA_BLOCKED 프레임을 생성한다.

애플리케이션이 모든 스트림 데이터가 전송되었음을 나타내고 FIN 비트가 포함된 STREAM 프레임이 전송되면, 스트림의 송신 부분은 "Data Sent" 상태로 들어간다. 이 상태에서 엔드포인트는 필요한 경우에만 스트림 데이터를 재전송한다. 엔드포인트는 이 상태의 스트림에 대해 흐름 제어 한도를 확인하거나 STREAM_DATA_BLOCKED 프레임을 보낼 필요가 없다. 피어가 최종 스트림 오프셋을 수신할 때까지 MAX_STREAM_DATA 프레임이 수신될 수 있다. 엔드포인트는 이 상태의 스트림에 대해 피어로부터 수신한 모든 MAX_STREAM_DATA 프레임을 안전하게 무시할 수 있다.

모든 스트림 데이터가 성공적으로 확인 응답되면, 스트림의 송신 부분은 "Data Recvd" 상태로 들어가며, 이는 종단 상태이다.

"Ready", "Send" 또는 "Data Sent" 중 하나의 상태에서, 애플리케이션은 스트림 데이터 전송을 포기하려 한다는 신호를 보낼 수 있다. 또는 엔드포인트가 피어로부터 STOP_SENDING 프레임을 수신할 수 있다. 두 경우 모두 엔드포인트는 RESET_STREAM 프레임을 보내며, 이로 인해 스트림은 "Reset Sent" 상태로 들어간다.

엔드포인트는 스트림을 언급하는 첫 번째 프레임으로 RESET_STREAM을 보낼 수 MAY 있다. 이는 해당 스트림의 송신 부분을 열고 즉시 "Reset Sent" 상태로 전이하게 한다.

RESET_STREAM을 포함하는 패킷이 확인 응답되면, 스트림의 송신 부분은 "Reset Recvd" 상태로 들어가며, 이는 종단 상태이다.

3.2. 수신 스트림 상태

Figure 3은 피어로부터 데이터를 수신하는 스트림 부분의 상태를 보여준다. 스트림의 수신 부분에 대한 상태는 피어의 스트림 송신 부분 상태 중 일부만 반영한다. 스트림의 수신 부분은 "Ready" 상태처럼 관찰할 수 없는 송신 부분의 상태를 추적하지 않는다. 대신 스트림의 수신 부분은 애플리케이션으로의 데이터 전달을 추적하며, 그중 일부는 송신자가 관찰할 수 없다.

       o
       | Recv STREAM / STREAM_DATA_BLOCKED / RESET_STREAM
       | Create Bidirectional Stream (Sending)
       | Recv MAX_STREAM_DATA / STOP_SENDING (Bidirectional)
       | Create Higher-Numbered Stream
       v
   +-------+
   | Recv  | Recv RESET_STREAM
   |       |-----------------------.
   +-------+                       |
       |                           |
       | Recv STREAM + FIN         |
       v                           |
   +-------+                       |
   | Size  | Recv RESET_STREAM     |
   | Known |---------------------->|
   +-------+                       |
       |                           |
       | Recv All Data             |
       v                           v
   +-------+ Recv RESET_STREAM +-------+
   | Data  |--- (optional) --->| Reset |
   | Recvd |  Recv All Data    | Recvd |
   +-------+<-- (optional) ----+-------+
       |                           |
       | App Read All Data         | App Read Reset
       v                           v
   +-------+                   +-------+
   | Data  |                   | Reset |
   | Read  |                   | Read  |
   +-------+                   +-------+
Figure 3: 스트림의 수신 부분에 대한 상태

피어가 개시한 스트림의 수신 부분(클라이언트의 경우 유형 1 및 3, 서버의 경우 0 및 2)은 해당 스트림에 대한 첫 번째 STREAM, STREAM_DATA_BLOCKED 또는 RESET_STREAM 프레임이 수신될 때 생성된다. 피어가 개시한 양방향 스트림의 경우, 스트림의 송신 부분에 대한 MAX_STREAM_DATA 또는 STOP_SENDING 프레임을 수신하는 것도 수신 부분을 생성한다. 스트림의 수신 부분에 대한 초기 상태는 "Recv"이다.

양방향 스트림의 경우, 엔드포인트가 개시한 송신 부분(클라이언트의 경우 유형 0, 서버의 경우 유형 1)이 "Ready" 상태로 들어갈 때 수신 부분이 "Recv" 상태로 들어간다.

엔드포인트는 해당 스트림에 대해 피어로부터 MAX_STREAM_DATA 또는 STOP_SENDING 프레임을 수신하면 양방향 스트림을 연다. 열리지 않은 스트림에 대한 MAX_STREAM_DATA 프레임을 수신하는 것은 원격 피어가 스트림을 열었고 흐름 제어 크레딧을 제공하고 있음을 나타낸다. 열리지 않은 스트림에 대한 STOP_SENDING 프레임을 수신하는 것은 원격 피어가 더 이상 이 스트림에서 데이터를 수신하기를 원하지 않음을 나타낸다. 패킷이 손실되거나 재정렬되는 경우, 두 프레임 모두 STREAM 또는 STREAM_DATA_BLOCKED 프레임보다 먼저 도착할 수 있다.

스트림이 생성되기 전에, 같은 유형의 더 낮은 번호의 스트림 ID를 가진 모든 스트림은 생성되어야 MUST 한다. 이는 스트림 생성 순서가 양쪽 엔드포인트에서 일관되도록 보장한다.

"Recv" 상태에서 엔드포인트는 STREAM 및 STREAM_DATA_BLOCKED 프레임을 수신한다. 들어오는 데이터는 버퍼링되며 애플리케이션에 전달하기 위해 올바른 순서로 재조립될 수 있다. 애플리케이션이 데이터를 소비하고 버퍼 공간이 사용 가능해지면, 엔드포인트는 피어가 더 많은 데이터를 보낼 수 있도록 MAX_STREAM_DATA 프레임을 보낸다.

FIN 비트가 있는 STREAM 프레임이 수신되면, 스트림의 최종 크기를 알 수 있다. Section 4.5를 참조한다. 그런 다음 스트림의 수신 부분은 "Size Known" 상태로 들어간다. 이 상태에서 엔드포인트는 더 이상 MAX_STREAM_DATA 프레임을 보낼 필요가 없으며, 스트림 데이터의 재전송만 수신한다.

스트림의 모든 데이터가 수신되면, 수신 부분은 "Data Recvd" 상태로 들어간다. 이는 "Size Known"으로의 전이를 일으킨 동일한 STREAM 프레임을 수신한 결과로 발생할 수 있다. 모든 데이터가 수신된 후에는 해당 스트림에 대한 모든 STREAM 또는 STREAM_DATA_BLOCKED 프레임을 폐기할 수 있다.

"Data Recvd" 상태는 스트림 데이터가 애플리케이션에 전달될 때까지 지속된다. 스트림 데이터가 전달되면, 스트림은 "Data Read" 상태로 들어가며, 이는 종단 상태이다.

"Recv" 또는 "Size Known" 상태에서 RESET_STREAM 프레임을 수신하면 스트림은 "Reset Recvd" 상태로 들어간다. 이는 애플리케이션으로의 스트림 데이터 전달을 중단시킬 수 있다.

RESET_STREAM을 수신했을 때 모든 스트림 데이터가 이미 수신되어 있을 수 있다 (즉, "Data Recvd" 상태). 마찬가지로 RESET_STREAM 프레임을 수신한 후에도 남은 스트림 데이터가 도착할 수 있다("Reset Recvd" 상태). 구현은 이 상황을 원하는 방식으로 자유롭게 관리할 수 있다.

RESET_STREAM을 보내는 것은 엔드포인트가 스트림 데이터의 전달을 보장할 수 없음을 의미한다. 그러나 RESET_STREAM이 수신되었다고 해서 스트림 데이터가 전달되지 않아야 한다는 요구사항은 없다. 구현은 스트림 데이터 전달을 중단하고, 소비되지 않은 모든 데이터를 폐기하며, RESET_STREAM의 수신을 알릴 수 MAY 있다. 스트림 데이터가 완전히 수신되어 애플리케이션이 읽을 수 있도록 버퍼링된 경우, RESET_STREAM 신호는 억제되거나 보류될 수 있다. RESET_STREAM이 억제되면, 스트림의 수신 부분은 "Data Recvd" 상태로 남는다.

애플리케이션이 스트림이 재설정되었음을 나타내는 신호를 수신하면, 스트림의 수신 부분은 "Reset Read" 상태로 전이되며, 이는 종단 상태이다.

3.3. 허용된 프레임 유형

스트림의 송신자는 송신자 또는 수신자 어느 쪽에서든 스트림의 상태에 영향을 주는 세 가지 프레임 유형만 보낸다. STREAM(Section 19.8), STREAM_DATA_BLOCKED(Section 19.13) 및 RESET_STREAM (Section 19.4)이다.

송신자는 종단 상태("Data Recvd" 또는 "Reset Recvd")에서 이러한 프레임 중 어느 것도 보내서는 MUST NOT 안 된다. 송신자는 "Reset Sent" 상태 또는 어떤 종단 상태에 있는 스트림에 대해 STREAM 또는 STREAM_DATA_BLOCKED 프레임을 보내서는 MUST NOT 안 된다. 즉, RESET_STREAM 프레임을 보낸 이후에는 보내면 안 된다. 수신자는 이 세 가지 프레임 중 어느 것이든, 이를 운반하는 패킷의 지연 전달 가능성 때문에, 어떤 상태에서도 수신할 수 있다.

스트림의 수신자는 MAX_STREAM_DATA 프레임 (Section 19.10)과 STOP_SENDING 프레임(Section 19.5)을 보낸다.

수신자는 "Recv" 상태에서만 MAX_STREAM_DATA 프레임을 보낸다. 수신자는 RESET_STREAM 프레임을 아직 수신하지 않은 모든 상태, 즉 "Reset Recvd" 또는 "Reset Read" 이외의 상태에서 STOP_SENDING 프레임을 보낼 수 MAY 있다. 그러나 "Data Recvd" 상태에서는 모든 스트림 데이터가 수신되었으므로 STOP_SENDING 프레임을 보내는 데 큰 가치가 없다. 송신자는 패킷의 지연 전달 결과로 이 두 유형의 프레임 중 어느 것이든 어떤 상태에서도 수신할 수 있다.

3.4. 양방향 스트림 상태

양방향 스트림은 송신 부분과 수신 부분으로 구성된다. 구현은 양방향 스트림의 상태를 송신 및 수신 스트림 상태의 합성으로 표현할 수 있다. 가장 단순한 모델은 송신 또는 수신 부분 중 어느 하나가 비종단 상태에 있으면 스트림을 "open"으로, 송신 및 수신 스트림이 모두 종단 상태에 있으면 "closed"로 나타낸다.

Table 2는 HTTP/2 [HTTP2]에 정의된 스트림 상태와 느슨하게 대응하는 양방향 스트림 상태의 더 복잡한 매핑을 보여준다. 이는 스트림의 송신 또는 수신 부분에 있는 여러 상태가 동일한 합성 상태에 매핑됨을 보여준다. 이는 이러한 매핑의 한 가지 가능성일 뿐이라는 점에 유의한다. 이 매핑은 "closed" 또는 "half-closed" 상태로 전이하기 전에 데이터가 확인 응답되어야 함을 요구한다.

Table 2: 스트림 상태를 HTTP/2로 매핑하는 가능한 방식
송신 부분 수신 부분 합성 상태
No Stream / Ready No Stream / Recv (*1) idle
Ready / Send / Data Sent Recv / Size Known open
Ready / Send / Data Sent Data Recvd / Data Read half-closed (remote)
Ready / Send / Data Sent Reset Recvd / Reset Read half-closed (remote)
Data Recvd Recv / Size Known half-closed (local)
Reset Sent / Reset Recvd Recv / Size Known half-closed (local)
Reset Sent / Reset Recvd Data Recvd / Data Read closed
Reset Sent / Reset Recvd Reset Recvd / Reset Read closed
Data Recvd Data Recvd / Data Read closed
Data Recvd Reset Recvd / Reset Read closed

3.5. 요청된 상태 전이

애플리케이션이 스트림에서 수신 중인 데이터에 더 이상 관심이 없다면, 스트림 읽기를 중단하고 애플리케이션 오류 코드를 지정할 수 있다.

스트림이 "Recv" 또는 "Size Known" 상태에 있다면, 전송 계층은 반대 방향의 스트림 닫기를 유도하기 위해 STOP_SENDING 프레임을 보내 이를 신호해야 SHOULD 한다. 이는 일반적으로 수신 애플리케이션이 스트림에서 수신하는 데이터를 더 이상 읽지 않음을 나타내지만, 들어오는 데이터가 무시될 것이라는 보장은 아니다.

STOP_SENDING 프레임을 보낸 후 수신된 STREAM 프레임은, 수신 시 폐기될 수 있더라도, 여전히 연결 및 스트림 흐름 제어에 계산된다.

STOP_SENDING 프레임은 수신 엔드포인트에게 RESET_STREAM 프레임을 보내도록 요청한다. STOP_SENDING 프레임을 수신한 엔드포인트는 스트림이 "Ready" 또는 "Send" 상태에 있으면 RESET_STREAM 프레임을 보내야 MUST 한다. 스트림이 "Data Sent" 상태에 있으면, 엔드포인트는 미처리 데이터를 포함하는 패킷이 확인 응답되거나 손실로 선언될 때까지 RESET_STREAM 프레임 전송을 지연할 수 MAY 있다. 미처리 데이터가 손실로 선언되면, 엔드포인트는 데이터를 재전송하는 대신 RESET_STREAM 프레임을 보내야 SHOULD 한다.

엔드포인트는 STOP_SENDING 프레임의 오류 코드를 자신이 보내는 RESET_STREAM 프레임에 복사해야 SHOULD 하지만, 어떤 애플리케이션 오류 코드도 사용할 수 있다. STOP_SENDING 프레임을 보낸 엔드포인트는 이후 해당 스트림에 대해 수신한 모든 RESET_STREAM 프레임의 오류 코드를 무시할 수 MAY 있다.

STOP_SENDING은 피어에 의해 재설정되지 않은 스트림에 대해서만 보내야 SHOULD 한다. STOP_SENDING은 "Recv" 또는 "Size Known" 상태의 스트림에 가장 유용하다.

이전 STOP_SENDING을 포함하는 패킷이 손실되면 엔드포인트는 또 다른 STOP_SENDING 프레임을 보낼 것으로 예상된다. 그러나 스트림에 대해 모든 스트림 데이터 또는 RESET_STREAM 프레임 중 하나가 수신되면, 즉 스트림이 "Recv" 또는 "Size Known" 이외의 어떤 상태에 있으면, STOP_SENDING 프레임을 보내는 것은 불필요하다.

양방향 스트림의 양방향 모두를 종료하려는 엔드포인트는 RESET_STREAM 프레임을 보내 한 방향을 종료할 수 있으며, STOP_SENDING 프레임을 보내 반대 방향의 신속한 종료를 유도할 수 있다.

4. 흐름 제어

수신자는 빠른 송신자가 자신을 압도하거나 악의적인 송신자가 대량의 메모리를 소비하는 것을 방지하기 위해, 버퍼링해야 하는 데이터 양을 제한할 필요가 있다. 수신자가 연결에 대한 메모리 약속을 제한할 수 있게 하기 위해, 스트림은 개별적으로 그리고 연결 전체에 걸쳐 흐름 제어된다. QUIC 수신자는 4.14.2 섹션에 설명된 것처럼, 송신자가 특정 스트림에서 보낼 수 있는 데이터의 최대량과 모든 스트림 전체에서 어느 시점에든 보낼 수 있는 최대량을 제어한다.

마찬가지로, 연결 내 동시성을 제한하기 위해 QUIC 엔드포인트는 피어가 개시할 수 있는 누적 스트림 수의 최대값을 제어한다. 이는 Section 4.6에 설명되어 있다.

CRYPTO 프레임으로 전송되는 데이터는 스트림 데이터와 같은 방식으로 흐름 제어되지 않는다. QUIC는 과도한 데이터 버퍼링을 피하기 위해 암호화 프로토콜 구현에 의존한다. [QUIC-TLS]를 참조한다. 여러 계층에서의 과도한 버퍼링을 피하기 위해, QUIC 구현은 암호화 프로토콜 구현이 자신의 버퍼링 한도를 전달할 수 있는 인터페이스를 제공해야 SHOULD 한다.

4.1. 데이터 흐름 제어

QUIC는 수신자가 특정 스트림 또는 전체 연결에 대해 수신할 준비가 된 총 바이트의 한도를 알리는 한도 기반 흐름 제어 방식을 사용한다. 이는 QUIC에서 두 수준의 데이터 흐름 제어로 이어진다:

  • 스트림 흐름 제어는 각 스트림에서 전송할 수 있는 데이터 양을 제한하여 단일 스트림이 연결의 전체 수신 버퍼를 소비하지 못하게 한다.
  • 연결 흐름 제어는 모든 스트림의 STREAM 프레임으로 전송되는 스트림 데이터의 총 바이트 수를 제한하여 송신자가 해당 연결에 대한 수신자의 버퍼 용량을 초과하지 못하게 한다.

송신자는 어느 한도도 초과하여 데이터를 보내서는 MUST NOT 안 된다.

수신자는 핸드셰이크 중 전송 매개변수 (Section 7.4)를 통해 모든 스트림의 초기 한도를 설정한다. 이후 수신자는 더 큰 한도를 알리기 위해 MAX_STREAM_DATA 프레임(Section 19.10) 또는 MAX_DATA 프레임 (Section 19.9)을 송신자에게 보낸다.

수신자는 해당 스트림 ID를 가진 MAX_STREAM_DATA 프레임을 보내 스트림에 대해 더 큰 한도를 알릴 수 있다. MAX_STREAM_DATA 프레임은 스트림의 최대 절대 바이트 오프셋을 나타낸다. 수신자는 해당 스트림에서 소비된 데이터의 현재 오프셋을 기준으로 알릴 흐름 제어 오프셋을 결정할 수 있다.

수신자는 모든 스트림의 절대 바이트 오프셋 합계의 최대값을 나타내는 MAX_DATA 프레임을 보내 연결에 대해 더 큰 한도를 알릴 수 있다. 수신자는 모든 스트림에서 수신된 바이트의 누적 합계를 유지하며, 이는 광고된 연결 또는 스트림 데이터 한도의 위반을 확인하는 데 사용된다. 수신자는 모든 스트림에서 소비된 바이트 합계를 기준으로 알릴 최대 데이터 한도를 결정할 수 있다.

수신자가 연결 또는 스트림에 대한 한도를 알린 뒤에는, 더 작은 한도를 알리는 것이 오류는 아니지만, 더 작은 한도는 효과가 없다.

송신자가 광고된 연결 또는 스트림 데이터 한도를 위반하면, 수신자는 FLOW_CONTROL_ERROR 유형의 오류로 연결을 닫아야 MUST 한다. 오류 처리에 대한 세부사항은 Section 11을 참조한다.

송신자는 흐름 제어 한도를 증가시키지 않는 모든 MAX_STREAM_DATA 또는 MAX_DATA 프레임을 무시해야 MUST 한다.

송신자가 한도까지 데이터를 보냈다면 새 데이터를 보낼 수 없으며 차단된 것으로 간주된다. 송신자는 쓸 데이터가 있지만 흐름 제어 한도에 의해 차단되었음을 수신자에게 나타내기 위해 STREAM_DATA_BLOCKED 또는 DATA_BLOCKED 프레임을 보내야 SHOULD 한다. 송신자가 유휴 타임아웃(Section 10.1)보다 긴 기간 동안 차단되면, 송신자에게 전송 가능한 데이터가 있더라도 수신자는 연결을 닫을 수 있다. 연결이 닫히지 않도록 하기 위해, 흐름 제어로 제한된 송신자는 전송 중인 ack-eliciting 패킷이 없을 때 주기적으로 STREAM_DATA_BLOCKED 또는 DATA_BLOCKED 프레임을 보내야 SHOULD 한다.

4.2. 흐름 제어 한도 증가

구현은 MAX_STREAM_DATA 및 MAX_DATA 프레임에서 언제 얼마나 많은 크레딧을 알릴지 결정하지만, 이 섹션은 몇 가지 고려사항을 제공한다.

송신자가 차단되는 것을 피하기 위해, 수신자는 한 왕복 시간 내에 MAX_STREAM_DATA 또는 MAX_DATA 프레임을 여러 번 보내거나, 프레임 손실과 이후 복구를 위한 시간을 허용할 만큼 충분히 일찍 보낼 수 MAY 있다.

제어 프레임은 연결 오버헤드에 기여한다. 따라서 작은 변경으로 MAX_STREAM_DATA 및 MAX_DATA 프레임을 자주 보내는 것은 바람직하지 않다. 반면에 업데이트가 덜 빈번하면 송신자가 차단되는 것을 피하기 위해 한도에 더 큰 증분이 필요하며, 이는 수신자에서 더 큰 리소스 약속을 요구한다. 알릴 한도의 크기를 결정할 때 리소스 약속과 오버헤드 사이에는 절충이 있다.

수신자는 왕복 시간 추정치와 수신 애플리케이션이 데이터를 소비하는 속도에 기반하여 알릴 추가 크레딧의 빈도와 양을 조정하는 자동 조정 메커니즘을 사용할 수 있으며, 이는 일반적인 TCP 구현과 유사하다. 최적화로서, 엔드포인트는 보낼 다른 프레임이 있을 때만 흐름 제어와 관련된 프레임을 보내도록 할 수 있어, 흐름 제어가 추가 패킷 전송을 유발하지 않도록 할 수 있다.

차단된 송신자는 STREAM_DATA_BLOCKED 또는 DATA_BLOCKED 프레임을 보낼 필요가 없다. 따라서 수신자는 MAX_STREAM_DATA 또는 MAX_DATA 프레임을 보내기 전에 STREAM_DATA_BLOCKED 또는 DATA_BLOCKED 프레임을 기다려서는 MUST NOT 안 된다. 그렇게 하면 송신자가 연결의 나머지 동안 차단될 수 있다. 송신자가 이러한 프레임을 보내더라도, 이를 기다리면 송신자는 적어도 전체 왕복 시간 동안 차단된다.

송신자가 차단된 후 크레딧을 수신하면, 그 응답으로 많은 양의 데이터를 보낼 수 있어 단기적인 혼잡이 발생할 수 있다. 송신자가 이 혼잡을 피할 수 있는 방법에 대한 논의는 Section 7.7 of [QUIC-RECOVERY]를 참조한다.

4.3. 흐름 제어 성능

엔드포인트가 피어가 항상 이 연결의 대역폭-지연 곱보다 큰 사용 가능한 흐름 제어 크레딧을 갖도록 보장할 수 없다면, 그 수신 처리량은 흐름 제어에 의해 제한된다.

패킷 손실은 수신 버퍼에 공백을 만들 수 있으며, 이는 애플리케이션이 데이터를 소비하고 수신 버퍼 공간을 해제하는 것을 방해한다.

흐름 제어 한도를 적시에 업데이트하면 성능을 향상시킬 수 있다. 흐름 제어 업데이트만 제공하기 위해 패킷을 보내면 네트워크 부하가 증가하고 성능에 악영향을 줄 수 있다. ACK 프레임과 같은 다른 프레임과 함께 흐름 제어 업데이트를 보내면 이러한 업데이트의 비용이 줄어든다.

4.4. 스트림 취소 처리

엔드포인트는 연결 수준 흐름 제어를 위해 모든 바이트를 계산할 수 있도록, 모든 스트림에서 소비된 흐름 제어 크레딧의 양에 대해 결국 합의해야 한다.

RESET_STREAM 프레임을 수신하면, 엔드포인트는 일치하는 스트림에 대한 상태를 해제하고 해당 스트림에 도착하는 추가 데이터를 무시한다.

RESET_STREAM은 스트림의 한 방향을 갑작스럽게 종료한다. 양방향 스트림의 경우, RESET_STREAM은 반대 방향의 데이터 흐름에 영향을 주지 않는다. 두 엔드포인트는 종료되지 않은 방향이 종단 상태에 들어갈 때까지 해당 방향의 스트림 흐름 제어 상태를 유지해야 MUST 한다.

4.5. 스트림 최종 크기

최종 크기는 스트림이 소비한 흐름 제어 크레딧의 양이다. 스트림의 모든 연속 바이트가 한 번씩 전송되었다고 가정하면, 최종 크기는 전송된 바이트 수이다. 더 일반적으로는, 스트림에서 전송된 가장 큰 오프셋을 가진 바이트의 오프셋보다 1 큰 값이며, 바이트가 전송되지 않았다면 0이다.

송신자는 스트림이 어떻게 종료되든 관계없이 스트림의 최종 크기를 수신자에게 신뢰성 있게 항상 전달한다. 최종 크기는 FIN 플래그가 있는 STREAM 프레임의 Offset 및 Length 필드의 합이며, 이러한 필드가 암시적일 수 있음에 유의한다. 또는 RESET_STREAM 프레임의 Final Size 필드가 이 값을 운반한다. 이는 양쪽 엔드포인트가 해당 스트림에서 송신자가 소비한 흐름 제어 크레딧 양에 대해 합의하도록 보장한다.

엔드포인트는 스트림의 수신 부분이 "Size Known" 또는 "Reset Recvd" 상태 (Section 3)에 들어갈 때 스트림의 최종 크기를 알게 된다. 수신자는 연결 수준 흐름 제어기에서 스트림에 전송된 모든 바이트를 계산하기 위해 스트림의 최종 크기를 사용해야 MUST 한다.

엔드포인트는 최종 크기 이상에서 스트림에 데이터를 보내서는 MUST NOT 안 된다.

스트림의 최종 크기가 알려지면, 이는 변경될 수 없다. 스트림의 최종 크기 변경을 나타내는 RESET_STREAM 또는 STREAM 프레임이 수신되면, 엔드포인트는 FINAL_SIZE_ERROR 유형의 오류로 응답해야 SHOULD 한다. 오류 처리에 대한 세부사항은 Section 11을 참조한다. 수신자는 스트림이 닫힌 후에도 최종 크기 이상에서 데이터를 수신하는 것을 FINAL_SIZE_ERROR 유형의 오류로 처리해야 SHOULD 한다. 이러한 오류를 생성하는 것은 의무가 아니다. 엔드포인트가 이러한 오류를 생성하도록 요구하면, 닫힌 스트림에 대한 최종 크기 상태도 유지해야 하며, 이는 상당한 상태 약속을 의미할 수 있기 때문이다.

4.6. 동시성 제어

엔드포인트는 피어가 열 수 있는 수신 스트림의 누적 수를 제한한다. 스트림 ID가 (max_streams * 4 + first_stream_id_of_type)보다 작은 스트림만 열 수 있다. Table 1을 참조한다. 초기 한도는 전송 매개변수에서 설정된다. Section 18.2를 참조한다. 이후 한도는 MAX_STREAMS 프레임을 사용해 알린다. Section 19.11을 참조한다. 단방향 및 양방향 스트림에는 별도의 한도가 적용된다.

max_streams 전송 매개변수 또는 MAX_STREAMS 프레임이 260보다 큰 값으로 수신되면, 이는 가변 길이 정수로 표현할 수 없는 최대 스트림 ID를 허용하게 된다. Section 16을 참조한다. 어느 하나가 수신되면, 해당 값이 전송 매개변수에서 수신된 경우 TRANSPORT_PARAMETER_ERROR 유형의 연결 오류로, 프레임에서 수신된 경우 FRAME_ENCODING_ERROR 유형의 연결 오류로, 연결을 즉시 닫아야 MUST 한다. Section 10.2를 참조한다.

엔드포인트는 피어가 설정한 한도를 초과해서는 MUST NOT 안 된다. 자신이 보낸 한도를 초과하는 스트림 ID를 가진 프레임을 수신한 엔드포인트는 이를 STREAM_LIMIT_ERROR 유형의 연결 오류로 처리해야 MUST 한다. 오류 처리에 대한 세부사항은 Section 11을 참조한다.

수신자가 MAX_STREAMS 프레임을 사용해 스트림 한도를 알린 뒤에는, 더 작은 한도를 알리는 것이 효과가 없다. 스트림 한도를 증가시키지 않는 MAX_STREAMS 프레임은 무시되어야 MUST 한다.

스트림 및 연결 흐름 제어와 마찬가지로, 이 문서는 구현이 MAX_STREAMS를 통해 언제 얼마나 많은 스트림을 피어에게 알릴지 결정하도록 맡긴다. 구현은 피어에게 제공되는 스트림 수를 대략 일정하게 유지하기 위해, 스트림이 닫힐 때 한도를 늘리기로 선택할 수 있다.

피어의 한도로 인해 새 스트림을 열 수 없는 엔드포인트는 STREAMS_BLOCKED 프레임(Section 19.14)을 보내야 SHOULD 한다. 이 신호는 디버깅에 유용한 것으로 간주된다. 엔드포인트는 추가 크레딧을 알리기 전에 이 신호를 수신하기를 기다려서는 MUST NOT 안 된다. 그렇게 하면 피어가 적어도 전체 왕복 시간 동안, 그리고 피어가 STREAMS_BLOCKED 프레임을 보내지 않기로 선택하면 잠재적으로 무기한 차단될 수 있기 때문이다.

5. 연결

QUIC 연결은 클라이언트와 서버 사이의 공유 상태이다.

각 연결은 핸드셰이크 단계로 시작하며, 이 동안 두 엔드포인트는 암호화 핸드셰이크 프로토콜 [QUIC-TLS]을 사용해 공유 비밀을 설정하고 애플리케이션 프로토콜을 협상한다. 핸드셰이크 (Section 7)는 두 엔드포인트가 통신할 의지가 있음을 확인하고 (Section 8.1), 연결에 대한 매개변수를 설정한다 (Section 7.4).

애플리케이션 프로토콜은 몇 가지 제한과 함께 핸드셰이크 단계 동안 연결을 사용할 수 있다. 0-RTT는 서버로부터 응답을 받기 전에 클라이언트가 애플리케이션 데이터를 보낼 수 있게 한다. 그러나 0-RTT는 재전송 공격에 대한 보호를 제공하지 않는다. Section 9.2 of [QUIC-TLS]를 참조한다. 서버도 클라이언트의 신원과 활성 여부를 확인할 수 있게 하는 최종 암호화 핸드셰이크 메시지를 수신하기 전에 클라이언트에게 애플리케이션 데이터를 보낼 수 있다. 이러한 기능은 애플리케이션 프로토콜이 일부 보안 보장을 줄이는 대신 지연 시간을 줄이는 옵션을 제공할 수 있게 한다.

연결 ID(Section 5.1)의 사용은 엔드포인트의 직접 선택으로 또는 미들박스의 변경으로 강제될 때 모두 연결이 새로운 네트워크 경로로 마이그레이션할 수 있게 한다. Section 9는 마이그레이션과 관련된 보안 및 프라이버시 문제에 대한 완화책을 설명한다.

더 이상 필요하지 않거나 원하지 않는 연결의 경우, 클라이언트와 서버가 연결을 종료하는 여러 방법이 있으며, 이는 Section 10에 설명되어 있다.

5.1. 연결 ID

각 연결은 연결 식별자 또는 연결 ID의 집합을 가지며, 각각은 연결을 식별할 수 있다. 연결 ID는 엔드포인트가 독립적으로 선택한다. 각 엔드포인트는 피어가 사용할 연결 ID를 선택한다.

연결 ID의 주요 기능은 하위 프로토콜 계층(UDP, IP)의 주소 지정 변경으로 인해 QUIC 연결의 패킷이 잘못된 엔드포인트로 전달되지 않도록 보장하는 것이다. 각 엔드포인트는 해당 연결 ID를 가진 패킷이 엔드포인트로 다시 라우팅되고 수신 시 엔드포인트에 의해 식별될 수 있도록 하는 구현별(그리고 아마도 배포별) 방법을 사용해 연결 ID를 선택한다.

엔드포인트의 협력 없이 관찰자가 동일한 연결에 대한 것으로 식별할 수 없는 패킷을 엔드포인트가 보낼 수 있도록 하기 위해 여러 연결 ID가 사용된다. Section 9.5를 참조한다.

연결 ID는 외부 관찰자(즉, 발급자와 협력하지 않는 관찰자)가 이를 같은 연결의 다른 연결 ID와 연관시키는 데 사용할 수 있는 어떤 정보도 포함해서는 MUST NOT 안 된다. 사소한 예로, 이는 동일한 연결에서 같은 연결 ID가 두 번 이상 발급되어서는 MUST NOT 안 된다는 것을 의미한다.

긴 헤더가 있는 패킷은 Source Connection ID 및 Destination Connection ID 필드를 포함한다. 이러한 필드는 새 연결에 대한 연결 ID를 설정하는 데 사용된다. 자세한 내용은 Section 7.2를 참조한다.

짧은 헤더가 있는 패킷(Section 17.3)은 Destination Connection ID만 포함하고 명시적 길이는 생략한다. Destination Connection ID 필드의 길이는 엔드포인트에 알려져 있을 것으로 예상된다. 연결 ID 기반으로 라우팅하는 로드 밸런서를 사용하는 엔드포인트는 연결 ID의 고정 길이에 대해 로드 밸런서와 합의하거나 인코딩 방식에 대해 합의할 수 있다. 고정된 부분은 명시적 길이를 인코딩할 수 있으며, 이를 통해 전체 연결 ID가 길이를 달리하면서도 로드 밸런서에서 사용될 수 있다.

Version Negotiation(Section 17.2.1) 패킷은 클라이언트가 선택한 연결 ID를 에코한다. 이는 클라이언트 쪽으로의 올바른 라우팅을 보장하고, 해당 패킷이 클라이언트가 보낸 패킷에 대한 응답임을 입증하기 위한 것이다.

올바른 엔드포인트로 라우팅하기 위해 연결 ID가 필요하지 않을 때는 길이가 0인 연결 ID를 사용할 수 있다. 그러나 길이가 0인 연결 ID를 사용하면서 동일한 로컬 IP 주소와 포트에서 연결을 다중화하면 피어 연결 마이그레이션, NAT 리바인딩 및 클라이언트 포트 재사용이 있을 때 실패가 발생한다. 엔드포인트는 이러한 프로토콜 기능이 사용되지 않음이 확실하지 않은 한, 길이가 0인 연결 ID를 가진 여러 동시 연결에 동일한 IP 주소와 포트를 사용해서는 MUST NOT 안 된다.

엔드포인트가 길이가 0이 아닌 연결 ID를 사용하는 경우, 해당 엔드포인트로 보내는 패킷에 대해 피어가 선택할 수 있는 연결 ID의 공급이 보장되도록 해야 한다. 이러한 연결 ID는 엔드포인트가 NEW_CONNECTION_ID 프레임(Section 19.15)을 사용해 제공한다.

5.1.1. 연결 ID 발급

각 연결 ID에는 NEW_CONNECTION_ID 또는 RETIRE_CONNECTION_ID 프레임이 같은 값을 참조하는 시점을 감지하는 데 도움이 되는 관련 시퀀스 번호가 있다. 엔드포인트가 발급한 초기 연결 ID는 핸드셰이크 중 긴 패킷 헤더의 Source Connection ID 필드(Section 17.2)에 전송된다. 초기 연결 ID의 시퀀스 번호는 0이다. preferred_address 전송 매개변수가 전송되면, 제공된 연결 ID의 시퀀스 번호는 1이다.

추가 연결 ID는 NEW_CONNECTION_ID 프레임(Section 19.15)을 사용해 피어에게 전달된다. 새로 발급되는 각 연결 ID의 시퀀스 번호는 1씩 증가해야 MUST 한다. 클라이언트가 자신이 보내는 첫 번째 Destination Connection ID 필드에 선택한 연결 ID와 Retry 패킷이 제공한 모든 연결 ID에는 시퀀스 번호가 할당되지 않는다.

엔드포인트가 연결 ID를 발급하면, 연결 기간 동안 또는 피어가 RETIRE_CONNECTION_ID 프레임 (Section 19.16)을 통해 연결 ID를 무효화할 때까지 해당 연결 ID를 운반하는 패킷을 수락해야 MUST 한다. 발급되었고 폐기되지 않은 연결 ID는 활성으로 간주된다. 모든 활성 연결 ID는 현재 연결과 함께 언제든, 어떤 패킷 유형에서든 사용할 수 있다. 여기에는 서버가 preferred_address 전송 매개변수를 통해 발급한 연결 ID도 포함된다.

엔드포인트는 피어가 사용 가능하고 사용되지 않은 연결 ID를 충분히 보유하도록 보장해야 SHOULD 한다. 엔드포인트는 active_connection_id_limit 전송 매개변수를 사용해 유지할 의향이 있는 활성 연결 ID의 수를 알린다. 엔드포인트는 피어의 한도보다 더 많은 연결 ID를 제공해서는 MUST NOT 안 된다. NEW_CONNECTION_ID 프레임이 Retire Prior To 필드에 충분히 큰 값을 포함하여 초과분의 폐기를 요구하는 경우, 엔드포인트는 피어의 한도를 일시적으로 초과하는 연결 ID를 보낼 수 MAY 있다.

NEW_CONNECTION_ID 프레임은 Retire Prior To 필드의 값에 따라 엔드포인트가 일부 활성 연결 ID를 추가하고 다른 연결 ID를 폐기하게 할 수 있다. NEW_CONNECTION_ID 프레임을 처리하고 활성 연결 ID를 추가 및 폐기한 뒤, 활성 연결 ID 수가 active_connection_id_limit 전송 매개변수에서 알린 값보다 크면, 엔드포인트는 CONNECTION_ID_LIMIT_ERROR 유형의 오류로 연결을 닫아야 MUST 한다.

피어가 연결 ID를 폐기하면 엔드포인트는 새 연결 ID를 제공해야 SHOULD 한다. 엔드포인트가 피어의 active_connection_id_limit보다 적은 연결 ID를 제공했다면, 이전에 사용되지 않은 연결 ID를 가진 패킷을 수신할 때 새 연결 ID를 제공할 수 MAY 있다. 엔드포인트는 연결 ID가 고갈될 위험을 피하기 위해 각 연결에 발급되는 연결 ID의 총 수를 제한할 수 MAY 있다. Section 10.3.2를 참조한다. 엔드포인트는 또한 피어가 발급된 연결 ID 수만큼 많은 경로를 통해 상호작용할 수 있으므로, 경로 검증 상태와 같은 경로별 상태 유지량을 줄이기 위해 연결 ID 발급을 제한할 수 MAY 있다.

마이그레이션을 시작하고 길이가 0이 아닌 연결 ID를 요구하는 엔드포인트는 피어가 마이그레이션 시 새 연결 ID를 사용할 수 있도록, 피어에게 사용 가능한 연결 ID 풀이 충분한지 보장해야 SHOULD 한다. 풀이 고갈되면 피어는 응답할 수 없기 때문이다.

핸드셰이크 중 길이가 0인 연결 ID를 선택한 엔드포인트는 새 연결 ID를 발급할 수 없다. 길이가 0인 Destination Connection ID 필드는 어떤 네트워크 경로를 통해서든 이러한 엔드포인트 쪽으로 보내는 모든 패킷에 사용된다.

5.1.2. 연결 ID 사용 및 폐기

엔드포인트는 연결 중 언제든지 피어에 대해 사용하는 연결 ID를 다른 사용 가능한 ID로 변경할 수 있다. 엔드포인트는 마이그레이션하는 피어에 대한 응답으로 연결 ID를 소비한다. 자세한 내용은 Section 9.5를 참조한다.

엔드포인트는 피어로부터 수신한 연결 ID의 집합을 유지하며, 그중 어느 것이든 패킷을 보낼 때 사용할 수 있다. 엔드포인트가 특정 연결 ID를 사용에서 제거하려면, RETIRE_CONNECTION_ID 프레임을 피어에게 보낸다. RETIRE_CONNECTION_ID 프레임을 보내는 것은 해당 연결 ID가 다시 사용되지 않을 것임을 나타내며, 피어에게 NEW_CONNECTION_ID 프레임을 사용해 새 연결 ID로 대체해 달라고 요청한다.

Section 9.5에서 논의한 것처럼, 엔드포인트는 연결 ID의 사용을 단일 로컬 주소에서 단일 목적지 주소로 보내는 패킷으로 제한한다. 엔드포인트는 연결 ID가 사용된 로컬 또는 목적지 주소 중 어느 하나를 더 이상 적극적으로 사용하지 않을 때 연결 ID를 폐기해야 SHOULD 한다.

엔드포인트는 특정 상황에서 이전에 발급한 연결 ID 수락을 중지해야 할 수 있다. 이러한 엔드포인트는 Retire Prior To 필드가 증가된 NEW_CONNECTION_ID 프레임을 보내 피어가 연결 ID를 폐기하도록 할 수 있다. 엔드포인트는 피어가 해당 연결 ID를 폐기할 때까지 이전에 발급한 연결 ID를 계속 수락해야 SHOULD 한다. 엔드포인트가 표시된 연결 ID를 더 이상 처리할 수 없다면, 연결을 닫을 수 MAY 있다.

증가된 Retire Prior To 필드를 수신하면, 피어는 해당 연결 ID 사용을 중지하고, 새로 제공된 연결 ID를 활성 연결 ID 집합에 추가하기 전에 RETIRE_CONNECTION_ID 프레임으로 이를 폐기해야 MUST 한다. 이 순서는 엔드포인트가 피어가 사용 가능한 연결 ID를 전혀 갖지 않게 될 가능성 없이, 그리고 피어가 active_connection_id_limit 전송 매개변수에서 설정한 한도를 초과하지 않고 모든 활성 연결 ID를 대체할 수 있게 한다. Section 18.2를 참조한다. 요청되었을 때 연결 ID 사용을 중지하지 않으면, 발급 엔드포인트가 활성 연결에서 해당 연결 ID를 계속 사용할 수 없게 되어 연결 실패가 발생할 수 있다.

엔드포인트는 로컬에서 폐기했지만 RETIRE_CONNECTION_ID 프레임이 아직 확인 응답되지 않은 연결 ID 수를 제한해야 SHOULD 한다. 엔드포인트는 active_connection_id_limit 전송 매개변수 값의 최소 두 배에 해당하는 수의 RETIRE_CONNECTION_ID 프레임을 전송하고 추적할 수 있도록 해야 SHOULD 한다. 엔드포인트는 연결 ID를 폐기하지 않고 잊어버려서는 MUST NOT 안 되지만, 이 한도를 초과하여 폐기가 필요한 연결 ID가 있는 것을 CONNECTION_ID_LIMIT_ERROR 유형의 연결 오류로 처리하기로 선택할 수 MAY 있다.

엔드포인트는 이전 Retire Prior To 값이 나타내는 모든 연결 ID를 폐기하는 RETIRE_CONNECTION_ID 프레임을 수신하기 전에는 Retire Prior To 필드의 업데이트를 발급해서는 SHOULD NOT 안 된다.

5.2. 패킷을 연결에 대응시키기

들어오는 패킷은 수신 시 분류된다. 패킷은 기존 연결과 연관될 수 있거나, 서버의 경우 새 연결을 만들 가능성이 있다.

엔드포인트는 패킷을 기존 연결과 연관시키려 한다. 패킷에 기존 연결에 해당하는 길이가 0이 아닌 Destination Connection ID가 있으면, QUIC는 해당 패킷을 그에 따라 처리한다. 둘 이상의 연결 ID가 하나의 연결과 연관될 수 있음에 유의한다. Section 5.1을 참조한다.

Destination Connection ID의 길이가 0이고 패킷의 주소 지정 정보가 엔드포인트가 길이 0 연결 ID를 가진 연결을 식별하는 데 사용하는 주소 지정 정보와 일치하면, QUIC는 해당 패킷을 그 연결의 일부로 처리한다. 엔드포인트는 목적지 IP와 포트만 사용하거나 식별을 위해 소스 및 목적지 주소를 모두 사용할 수 있지만, 이는 Section 5.1에 설명된 것처럼 연결을 취약하게 만든다.

엔드포인트는 기존 연결에 귀속될 수 없는 모든 패킷에 대해 Stateless Reset(Section 10.3)을 보낼 수 있다. Stateless Reset은 피어가 연결이 사용할 수 없게 되었음을 더 빠르게 식별할 수 있게 한다.

기존 연결과 일치한 패킷은 해당 연결의 상태와 일치하지 않으면 폐기된다. 예를 들어, 패킷이 연결의 프로토콜 버전과 다른 프로토콜 버전을 나타내거나, 예상 키가 사용 가능해진 뒤 패킷 보호 제거가 실패하면 패킷이 폐기된다.

Initial, Retry 또는 Version Negotiation처럼 강한 무결성 보호가 없는 유효하지 않은 패킷은 폐기될 수 MAY 있다. 엔드포인트는 오류를 발견하기 전에 이러한 패킷의 내용을 처리했다면 연결 오류를 생성해야 MUST 하거나, 그 처리 중 이루어진 모든 변경을 완전히 되돌려야 한다.

5.2.1. 클라이언트 패킷 처리

클라이언트로 전송되는 유효한 패킷은 항상 클라이언트가 선택한 값과 일치하는 Destination Connection ID를 포함한다. 길이가 0인 연결 ID를 수신하기로 선택한 클라이언트는 연결을 식별하기 위해 로컬 주소와 포트를 사용할 수 있다. Destination Connection ID 또는, 이 값의 길이가 0인 경우, 로컬 IP 주소와 포트를 기준으로 기존 연결과 일치하지 않는 패킷은 폐기된다.

패킷 재정렬 또는 손실로 인해, 클라이언트는 아직 계산하지 못한 키로 암호화된 연결의 패킷을 수신할 수 있다. 클라이언트는 이러한 패킷을 버릴 수 MAY 있거나, 나중에 키를 계산할 수 있게 하는 패킷을 예상하여 이를 버퍼링할 수 MAY 있다.

클라이언트가 처음 선택한 것과 다른 버전을 사용하는 패킷을 수신하면, 해당 패킷을 폐기해야 MUST 한다.

5.2.2. 서버 패킷 처리

서버가 지원되지 않는 버전을 나타내는 패킷을 수신하고, 해당 패킷이 지원되는 어떤 버전으로든 새 연결을 시작하기에 충분히 크다면, 서버는 Section 6.1에 설명된 대로 Version Negotiation 패킷을 보내야 SHOULD 한다. 서버는 Version Negotiation 패킷으로 응답하는 패킷 수를 제한할 수 MAY 있다. 서버는 지원되지 않는 버전을 지정하는 더 작은 패킷을 버려야 MUST 한다.

지원되지 않는 버전의 첫 번째 패킷은 어떤 버전별 필드에 대해서도 다른 의미와 인코딩을 사용할 수 있다. 특히, 버전마다 다른 패킷 보호 키가 사용될 수 있다. 특정 버전을 지원하지 않는 서버는 해당 패킷의 페이로드를 복호화하거나 결과를 올바르게 해석할 가능성이 낮다. 데이터그램이 충분히 길다면 서버는 Version Negotiation 패킷으로 응답해야 SHOULD 한다.

지원되는 버전이 있는 패킷 또는 Version 필드가 없는 패킷은 연결 ID를 사용하거나, 길이가 0인 연결 ID를 가진 패킷의 경우 로컬 주소와 포트를 사용해 연결에 대응된다. 이러한 패킷은 선택된 연결을 사용해 처리된다. 그렇지 않으면 서버는 아래 설명대로 계속한다.

패킷이 명세를 완전히 따르는 Initial 패킷이면, 서버는 핸드셰이크(Section 7)를 진행한다. 이는 서버가 클라이언트가 선택한 버전에 전념하도록 한다.

서버가 새 연결 수락을 거부하면, 오류 코드 CONNECTION_REFUSED가 있는 CONNECTION_CLOSE 프레임을 포함하는 Initial 패킷을 보내야 SHOULD 한다.

패킷이 0-RTT 패킷이면, 서버는 늦게 도착하는 Initial 패킷을 예상하여 이러한 패킷을 제한된 수만큼 버퍼링할 수 MAY 있다. 클라이언트는 서버 응답을 수신하기 전에는 Handshake 패킷을 보낼 수 없으므로, 서버는 그러한 패킷을 무시해야 SHOULD 한다.

서버는 다른 모든 상황에서 들어오는 패킷을 버려야 MUST 한다.

5.2.3. 단순 로드 밸런서에 대한 고려사항

서버 배포는 소스 및 목적지 IP 주소와 포트만 사용하여 서버들 사이에서 로드 밸런싱할 수 있다. 클라이언트의 IP 주소나 포트 변경은 패킷이 잘못된 서버로 전달되는 결과를 초래할 수 있다. 이러한 서버 배포는 클라이언트의 주소가 변경될 때 연결 연속성을 위해 다음 방법 중 하나를 사용할 수 있다.

  • 서버는 연결 ID를 기준으로 올바른 서버에 패킷을 전달하기 위해 대역 외 메커니즘을 사용할 수 있다.
  • 서버가 클라이언트가 처음 연결하는 주소 외에 전용 서버 IP 주소나 포트를 사용할 수 있다면, preferred_address 전송 매개변수를 사용하여 클라이언트가 연결을 해당 전용 주소로 이동하도록 요청할 수 있다. 클라이언트가 선호 주소를 사용하지 않기로 선택할 수 있음에 유의한다.

클라이언트 주소가 변경될 때 연결 연속성을 유지하기 위한 해결책을 구현하지 않은 배포의 서버는 disable_active_migration 전송 매개변수를 사용하여 마이그레이션이 지원되지 않음을 나타내야 SHOULD 한다. disable_active_migration 전송 매개변수는 클라이언트가 preferred_address 전송 매개변수에 따라 조치한 후의 연결 마이그레이션을 금지하지 않는다.

이 단순한 형태의 로드 밸런싱을 사용하는 서버 배포는 상태 없는 재설정 오라클의 생성을 피해야 MUST 한다. Section 21.11을 참조한다.

5.3. 연결에 대한 작업

이 문서는 QUIC용 API를 정의하지 않는다. 대신 애플리케이션 프로토콜이 의존할 수 있는 QUIC 연결을 위한 기능 집합을 정의한다. 애플리케이션 프로토콜은 QUIC 구현이 이 섹션에서 설명한 작업을 포함하는 인터페이스를 제공한다고 가정할 수 있다. 특정 애플리케이션 프로토콜과 함께 사용하도록 설계된 구현은 해당 프로토콜에서 사용되는 작업만 제공할 수 있다.

클라이언트 역할을 구현할 때, 애플리케이션 프로토콜은 다음을 수행할 수 있다:

  • Section 7에 설명된 교환을 시작하는 연결을 열 수 있다;
  • 사용 가능한 경우 Early Data를 활성화할 수 있다; 그리고
  • Early Data가 서버에 의해 수락되었는지 거부되었는지 통지받을 수 있다.

서버 역할을 구현할 때, 애플리케이션 프로토콜은 다음을 수행할 수 있다:

  • 들어오는 연결을 수신 대기할 수 있으며, 이는 Section 7에 설명된 교환을 준비한다;
  • Early Data가 지원되는 경우, 클라이언트에게 보내는 TLS 재개 티켓에 애플리케이션이 제어하는 데이터를 포함할 수 있다; 그리고
  • Early Data가 지원되는 경우, 클라이언트의 재개 티켓에서 애플리케이션이 제어하는 데이터를 검색하고 해당 정보를 기준으로 Early Data를 수락하거나 거부할 수 있다.

어느 역할에서든, 애플리케이션 프로토콜은 다음을 수행할 수 있다:

  • 전송 매개변수(Section 7.4)로 전달되는 각 유형의 허용된 초기 스트림 수에 대한 최소값을 구성할 수 있다;
  • 스트림과 연결 모두에 대해 흐름 제어 한도를 설정하여 수신 버퍼의 리소스 할당을 제어할 수 있다;
  • 핸드셰이크가 성공적으로 완료되었는지 또는 아직 진행 중인지 식별할 수 있다;
  • PING 프레임 (Section 19.2)을 생성하거나, 유휴 타임아웃이 만료되기 전에 전송 계층이 추가 프레임을 보내도록 요청함으로써(Section 10.1), 연결이 조용히 닫히지 않게 유지할 수 있다; 그리고
  • 연결을 즉시 닫을 수 있다(Section 10.2).

6. 버전 협상

버전 협상은 서버가 클라이언트가 사용한 버전을 지원하지 않음을 나타낼 수 있게 한다. 서버는 새 연결을 시작할 수 있는 각 패킷에 대한 응답으로 Version Negotiation 패킷을 보낸다. 자세한 내용은 Section 5.2를 참조한다.

클라이언트가 보낸 첫 번째 패킷의 크기는 서버가 Version Negotiation 패킷을 보낼지 여부를 결정한다. 여러 QUIC 버전을 지원하는 클라이언트는 자신이 보내는 첫 번째 UDP 데이터그램의 크기가 자신이 지원하는 모든 버전의 최소 데이터그램 크기 중 가장 큰 값이 되도록 해야 SHOULD 하며, 필요하다면 PADDING 프레임 (Section 19.1)을 사용한다. 이는 상호 지원되는 버전이 있는 경우 서버가 응답하도록 보장한다. 서버는 수신한 데이터그램이 다른 버전에 지정된 최소 크기보다 작으면 Version Negotiation 패킷을 보내지 않을 수 있다. Section 14.1을 참조한다.

6.1. Version Negotiation 패킷 보내기

클라이언트가 선택한 버전을 서버가 받아들일 수 없으면, 서버는 Version Negotiation 패킷으로 응답한다. Section 17.2.1을 참조한다. 여기에는 서버가 받아들일 버전 목록이 포함된다. 엔드포인트는 Version Negotiation 패킷을 수신한 것에 대한 응답으로 Version Negotiation 패킷을 보내서는 MUST NOT 안 된다.

이 시스템은 서버가 상태를 유지하지 않고도 지원되지 않는 버전의 패킷을 처리할 수 있게 한다. 응답으로 전송되는 Initial 패킷이나 Version Negotiation 패킷이 손실될 수 있지만, 클라이언트는 응답을 성공적으로 수신하거나 연결 시도를 포기할 때까지 새 패킷을 보낸다.

서버는 자신이 보내는 Version Negotiation 패킷 수를 제한할 수 MAY 있다. 예를 들어, 패킷을 0-RTT로 인식할 수 있는 서버는 결국 Initial 패킷을 수신할 것이라는 예상하에 0-RTT 패킷에 대한 응답으로 Version Negotiation 패킷을 보내지 않기로 선택할 수 있다.

6.2. Version Negotiation 패킷 처리

Version Negotiation 패킷은 향후 QUIC가 연결에 사용할 QUIC 버전을 협상할 수 있게 하는 기능을 정의할 수 있도록 설계되었다. 향후 표준 트랙 명세는 여러 QUIC 버전을 지원하는 구현이 이 버전을 사용하여 연결을 설정하려는 시도에 대한 응답으로 수신한 Version Negotiation 패킷에 반응하는 방식을 변경할 수 있다.

이 QUIC 버전만 지원하는 클라이언트는 Version Negotiation 패킷을 수신하면 다음 두 예외를 제외하고 현재 연결 시도를 포기해야 MUST 한다. 클라이언트는 이전 Version Negotiation 패킷을 포함하여 다른 어떤 패킷이라도 수신하고 성공적으로 처리했다면 모든 Version Negotiation 패킷을 폐기해야 MUST 한다. 클라이언트는 클라이언트가 선택한 QUIC 버전을 나열하는 Version Negotiation 패킷을 폐기해야 MUST 한다.

버전 협상을 수행하는 방법은 향후 표준 트랙 명세에서 정의할 향후 작업으로 남겨둔다. 특히, 그 향후 작업은 버전 다운그레이드 공격에 대한 견고성을 보장할 것이다. Section 21.12를 참조한다.

6.3. 예약된 버전 사용

서버가 향후 새 버전을 사용하려면 클라이언트가 지원되지 않는 버전을 올바르게 처리해야 한다. 일부 버전 번호( Section 15에 정의된 0x?a?a?a?a)는 버전 번호를 포함하는 필드에 포함되도록 예약되어 있다.

엔드포인트는 알 수 없거나 지원되지 않는 버전이 무시되는 모든 필드에 예약된 버전을 추가하여 피어가 해당 값을 올바르게 무시하는지 테스트할 수 MAY 있다. 예를 들어, 엔드포인트는 Version Negotiation 패킷에 예약된 버전을 포함할 수 있다. Section 17.2.1을 참조한다. 엔드포인트는 피어가 패킷을 올바르게 폐기하는지 테스트하기 위해 예약된 버전의 패킷을 보낼 수 MAY 있다.

7. 암호화 및 전송 핸드셰이크

QUIC는 연결 설정 지연 시간을 최소화하기 위해 결합된 암호화 및 전송 핸드셰이크에 의존한다. QUIC는 CRYPTO 프레임(Section 19.6)을 사용하여 암호화 핸드셰이크를 전송한다. 이 문서에 정의된 QUIC 버전은 0x00000001로 식별되며 [QUIC-TLS]에 설명된 TLS를 사용한다. 다른 QUIC 버전은 다른 암호화 핸드셰이크 프로토콜이 사용 중임을 나타낼 수 있다.

QUIC는 암호화 핸드셰이크 데이터에 대해 신뢰성 있고 정렬된 전달을 제공한다. QUIC 패킷 보호는 핸드셰이크 프로토콜의 가능한 많은 부분을 암호화하는 데 사용된다. 암호화 핸드셰이크는 다음 속성을 제공해야 MUST 한다:

CRYPTO 프레임은 서로 다른 패킷 번호 공간 (Section 12.3)에서 전송될 수 있다. 암호화 핸드셰이크 데이터의 정렬된 전달을 보장하기 위해 CRYPTO 프레임이 사용하는 오프셋은 각 패킷 번호 공간에서 0부터 시작한다.

Figure 4는 단순화된 핸드셰이크와 핸드셰이크를 진행하는 데 사용되는 패킷 및 프레임의 교환을 보여준다. 핸드셰이크 중 애플리케이션 데이터 교환은 가능한 경우 활성화되며, 별표("*")로 표시된다. 핸드셰이크가 완료되면 엔드포인트는 애플리케이션 데이터를 자유롭게 교환할 수 있다.

Client                                               Server

Initial (CRYPTO)
0-RTT (*)              ---------->
                                           Initial (CRYPTO)
                                         Handshake (CRYPTO)
                       <----------                1-RTT (*)
Handshake (CRYPTO)
1-RTT (*)              ---------->
                       <----------   1-RTT (HANDSHAKE_DONE)

1-RTT                  <=========>                    1-RTT
Figure 4: 단순화된 QUIC 핸드셰이크

엔드포인트는 Explicit Congestion Notification(ECN) 지원을 테스트하기 위해 핸드셰이크 중 전송되는 패킷을 사용할 수 있다. Section 13.4를 참조한다. 엔드포인트는 자신이 보낸 첫 번째 패킷을 확인 응답하는 ACK 프레임이 ECN 카운트를 운반하는지 관찰함으로써 ECN 지원을 검증한다. 이는 Section 13.4.2에 설명되어 있다.

엔드포인트는 애플리케이션 프로토콜을 명시적으로 협상해야 MUST 한다. 이는 사용 중인 프로토콜에 대해 의견 불일치가 발생하는 상황을 피한다.

7.1. 예시 핸드셰이크 흐름

TLS가 QUIC와 통합되는 방식의 세부사항은 [QUIC-TLS]에 제공되지만, 여기에는 몇 가지 예가 제공된다. 클라이언트 주소 검증을 지원하기 위한 이 교환의 확장은 Section 8.1.2에 표시되어 있다.

모든 주소 검증 교환이 완료되면, 암호화 핸드셰이크를 사용하여 암호화 키에 합의한다. 암호화 핸드셰이크는 Initial(Section 17.2.2) 및 Handshake (Section 17.2.4) 패킷으로 운반된다.

Figure 5는 1-RTT 핸드셰이크의 개요를 제공한다. 각 줄은 먼저 패킷 유형과 패킷 번호가 표시되고, 그 뒤에 일반적으로 해당 패킷에 포함되는 프레임이 표시된 QUIC 패킷을 보여준다. 예를 들어, 첫 번째 패킷은 packet number 0인 Initial 유형이며, ClientHello를 운반하는 CRYPTO 프레임을 포함한다.

여러 QUIC 패킷은, 서로 다른 패킷 유형이라도, 단일 UDP 데이터그램으로 병합될 수 있다. Section 12.2를 참조한다. 그 결과, 이 핸드셰이크는 최소 네 개의 UDP 데이터그램만으로 구성될 수도 있고, 더 많을 수도 있다 (혼잡 제어 및 증폭 방지와 같은 프로토콜 고유의 한도에 따른다). 예를 들어, 서버의 첫 번째 flight에는 Initial 패킷, Handshake 패킷 및 1-RTT 패킷의 "0.5-RTT data"가 포함된다.

Client                                                  Server

Initial[0]: CRYPTO[CH] ->

                                 Initial[0]: CRYPTO[SH] ACK[0]
                       Handshake[0]: CRYPTO[EE, CERT, CV, FIN]
                                 <- 1-RTT[0]: STREAM[1, "..."]

Initial[1]: ACK[0]
Handshake[0]: CRYPTO[FIN], ACK[0]
1-RTT[0]: STREAM[0, "..."], ACK[0] ->

                                          Handshake[1]: ACK[0]
         <- 1-RTT[1]: HANDSHAKE_DONE, STREAM[3, "..."], ACK[0]
Figure 5: 예시 1-RTT 핸드셰이크

Figure 6은 0-RTT 핸드셰이크와 단일 0-RTT 데이터 패킷이 있는 연결의 예를 보여준다. Section 12.3에 설명된 것처럼, 서버는 1-RTT 패킷에서 0-RTT 데이터를 확인 응답하고, 클라이언트는 같은 패킷 번호 공간에서 1-RTT 패킷을 보낸다는 점에 유의한다.

Client                                                  Server

Initial[0]: CRYPTO[CH]
0-RTT[0]: STREAM[0, "..."] ->

                                 Initial[0]: CRYPTO[SH] ACK[0]
                                  Handshake[0] CRYPTO[EE, FIN]
                          <- 1-RTT[0]: STREAM[1, "..."] ACK[0]

Initial[1]: ACK[0]
Handshake[0]: CRYPTO[FIN], ACK[0]
1-RTT[1]: STREAM[0, "..."] ACK[0] ->

                                          Handshake[1]: ACK[0]
         <- 1-RTT[1]: HANDSHAKE_DONE, STREAM[3, "..."], ACK[1]
Figure 6: 예시 0-RTT 핸드셰이크

7.2. 연결 ID 협상

연결 ID는 Section 5.1에 설명된 것처럼 패킷의 일관된 라우팅을 보장하는 데 사용된다. 긴 헤더에는 두 개의 연결 ID가 포함된다. Destination Connection ID는 패킷 수신자가 선택하며 일관된 라우팅을 제공하는 데 사용된다. Source Connection ID는 피어가 사용할 Destination Connection ID를 설정하는 데 사용된다.

핸드셰이크 중에는 긴 헤더(Section 17.2)가 있는 패킷을 사용하여 양쪽 엔드포인트가 사용할 연결 ID를 설정한다. 각 엔드포인트는 Source Connection ID 필드를 사용하여 자신에게 보내지는 패킷의 Destination Connection ID 필드에 사용될 연결 ID를 지정한다. 첫 번째 Initial 패킷을 처리한 후, 각 엔드포인트는 이후 자신이 보내는 패킷의 Destination Connection ID 필드를 자신이 수신한 Source Connection ID 필드의 값으로 설정한다.

서버로부터 Initial 또는 Retry 패킷을 이전에 수신하지 않은 클라이언트가 Initial 패킷을 보낼 때, 클라이언트는 Destination Connection ID 필드를 예측 불가능한 값으로 채운다. 이 Destination Connection ID는 길이가 최소 8바이트이어야 MUST 한다. 서버로부터 패킷을 수신할 때까지, 클라이언트는 이 연결의 모든 패킷에서 같은 Destination Connection ID 값을 사용해야 MUST 한다.

클라이언트가 보낸 첫 번째 Initial 패킷의 Destination Connection ID 필드는 Initial 패킷의 패킷 보호 키를 결정하는 데 사용된다. 이러한 키는 Retry 패킷을 수신한 후 변경된다. Section 5.2 of [QUIC-TLS]를 참조한다.

클라이언트는 자신이 선택한 값으로 Source Connection ID 필드를 채우고, 길이를 나타내도록 Source Connection ID Length 필드를 설정한다.

첫 번째 flight의 0-RTT 패킷은 클라이언트의 첫 번째 Initial 패킷과 동일한 Destination Connection ID 및 Source Connection ID 값을 사용한다.

서버로부터 Initial 또는 Retry 패킷을 처음 수신하면, 클라이언트는 서버가 제공한 Source Connection ID를 이후 패킷의 Destination Connection ID로 사용하며, 여기에는 모든 0-RTT 패킷도 포함된다. 이는 클라이언트가 연결 설정 중 Destination Connection ID 필드에 설정하는 연결 ID를 두 번 변경해야 할 수 있음을 의미한다. 한 번은 Retry 패킷에 대한 응답으로, 또 한 번은 서버의 Initial 패킷에 대한 응답으로 변경한다. 클라이언트가 서버로부터 유효한 Initial 패킷을 수신하면, 그 연결에서 이후 수신하는 Source Connection ID가 다른 모든 패킷을 폐기해야 MUST 한다.

클라이언트는 처음 수신한 Initial 또는 Retry 패킷에 대한 응답으로만 패킷 전송에 사용하는 Destination Connection ID를 변경해야 MUST 한다. 서버는 처음 수신한 Initial 패킷을 기준으로 패킷 전송에 사용하는 Destination Connection ID를 설정해야 MUST 한다. Destination Connection ID에 대한 추가 변경은 NEW_CONNECTION_ID 프레임에서 가져온 값인 경우에만 허용된다. 이후 Initial 패킷에 다른 Source Connection ID가 포함되면, 이는 폐기되어야 MUST 한다. 이는 Source Connection ID가 서로 다른 여러 Initial 패킷의 상태 없는 처리로 인해 발생할 수 있는 예측 불가능한 결과를 피한다.

엔드포인트가 보내는 Destination Connection ID는 연결 수명 동안, 특히 연결 마이그레이션(Section 9)에 대한 응답으로 변경될 수 있다. 자세한 내용은 Section 5.1.1을 참조한다.

7.3. 연결 ID 인증

각 엔드포인트가 핸드셰이크 중 연결 ID에 대해 내리는 선택은 모든 값을 전송 매개변수에 포함함으로써 인증된다. Section 7.4를 참조한다. 이는 핸드셰이크에 사용되는 모든 연결 ID가 암호화 핸드셰이크에 의해 인증되도록 보장한다.

각 엔드포인트는 자신이 보낸 첫 번째 Initial 패킷의 Source Connection ID 필드 값을 initial_source_connection_id 전송 매개변수에 포함한다. Section 18.2를 참조한다. 서버는 클라이언트로부터 수신한 첫 번째 Initial 패킷의 Destination Connection ID 필드를 original_destination_connection_id 전송 매개변수에 포함한다. 서버가 Retry 패킷을 보낸 경우, 이는 Retry 패킷을 보내기 전에 수신한 첫 번째 Initial 패킷을 가리킨다. Retry 패킷을 보내는 경우, 서버는 Retry 패킷의 Source Connection ID 필드도 retry_source_connection_id 전송 매개변수에 포함한다.

피어가 이러한 전송 매개변수에 제공한 값은 엔드포인트가 자신이 보낸 Initial 패킷의 Destination 및 Source Connection ID 필드에 사용한 값과 일치해야 MUST 한다(서버의 경우 수신한 값도 포함). 엔드포인트는 수신한 전송 매개변수가 수신한 연결 ID 값과 일치하는지 검증해야 MUST 한다. 연결 ID 값을 전송 매개변수에 포함하고 이를 검증하면, 공격자가 핸드셰이크 중 공격자가 선택한 연결 ID를 운반하는 패킷을 주입하여 성공적인 연결의 연결 ID 선택에 영향을 줄 수 없도록 보장한다.

엔드포인트는 어느 한 엔드포인트에서 initial_source_connection_id 전송 매개변수가 없거나, 서버에서 original_destination_connection_id 전송 매개변수가 없는 것을 TRANSPORT_PARAMETER_ERROR 유형의 연결 오류로 처리해야 MUST 한다.

엔드포인트는 다음을 TRANSPORT_PARAMETER_ERROR 또는 PROTOCOL_VIOLATION 유형의 연결 오류로 처리해야 MUST 한다:

  • Retry 패킷을 수신한 후 서버에서 retry_source_connection_id 전송 매개변수가 없음,
  • Retry 패킷을 수신하지 않았는데 retry_source_connection_id 전송 매개변수가 있음, 또는
  • 이러한 전송 매개변수에서 피어로부터 수신한 값과, Initial 패킷의 해당 Destination 또는 Source Connection ID 필드에 보낸 값 사이의 불일치.

길이가 0인 연결 ID가 선택되면, 해당 전송 매개변수는 길이가 0인 값으로 포함된다.

Figure 7은 완전한 핸드셰이크에 사용되는 연결 ID(DCID=Destination Connection ID, SCID=Source Connection ID)를 보여준다. Initial 패킷의 교환과, 핸드셰이크 중 설정된 연결 ID를 포함하는 이후 1-RTT 패킷 교환이 표시되어 있다.

Client                                                  Server

Initial: DCID=S1, SCID=C1 ->
                                  <- Initial: DCID=C1, SCID=S3
                             ...
1-RTT: DCID=S3 ->
                                             <- 1-RTT: DCID=C1
Figure 7: 핸드셰이크에서의 연결 ID 사용

Figure 8은 Retry 패킷을 포함하는 유사한 핸드셰이크를 보여준다.

Client                                                  Server

Initial: DCID=S1, SCID=C1 ->
                                    <- Retry: DCID=C1, SCID=S2
Initial: DCID=S2, SCID=C1 ->
                                  <- Initial: DCID=C1, SCID=S3
                             ...
1-RTT: DCID=S3 ->
                                             <- 1-RTT: DCID=C1
Figure 8: Retry가 있는 핸드셰이크에서의 연결 ID 사용

두 경우 모두(Figures 78), 클라이언트는 initial_source_connection_id 전송 매개변수의 값을 C1으로 설정한다.

핸드셰이크가 Retry를 포함하지 않는 경우(Figure 7), 서버는 original_destination_connection_id를 S1로 설정하고(이 값은 클라이언트가 선택한 값임에 유의), initial_source_connection_id를 S3로 설정한다. 이 경우 서버는 retry_source_connection_id 전송 매개변수를 포함하지 않는다.

핸드셰이크가 Retry를 포함하는 경우(Figure 8), 서버는 original_destination_connection_id를 S1로, retry_source_connection_id를 S2로, 그리고 initial_source_connection_id를 S3로 설정한다.

7.4. 전송 매개변수

연결 설정 중 양쪽 엔드포인트는 자신의 전송 매개변수에 대한 인증된 선언을 한다. 엔드포인트는 각 매개변수가 정의하는 제한을 준수해야 한다. 각 매개변수의 설명에는 그 처리 규칙이 포함된다.

전송 매개변수는 각 엔드포인트가 일방적으로 수행하는 선언이다. 각 엔드포인트는 피어가 선택한 값과 독립적으로 전송 매개변수 값을 선택할 수 있다.

전송 매개변수의 인코딩은 Section 18에 자세히 설명되어 있다.

QUIC는 인코딩된 전송 매개변수를 암호화 핸드셰이크에 포함한다. 핸드셰이크가 완료되면 피어가 선언한 전송 매개변수를 사용할 수 있다. 각 엔드포인트는 피어가 제공한 값을 검증한다.

정의된 각 전송 매개변수에 대한 정의는 Section 18.2에 포함되어 있다.

엔드포인트는 유효하지 않은 값을 가진 전송 매개변수를 수신한 것을 TRANSPORT_PARAMETER_ERROR 유형의 연결 오류로 처리해야 MUST 한다.

엔드포인트는 주어진 전송 매개변수 확장에서 같은 매개변수를 두 번 이상 보내서는 MUST NOT 안 된다. 엔드포인트는 중복된 전송 매개변수 수신을 TRANSPORT_PARAMETER_ERROR 유형의 연결 오류로 처리해야 SHOULD 한다.

엔드포인트는 핸드셰이크 중 연결 ID 협상을 인증하기 위해 전송 매개변수를 사용한다. Section 7.3을 참조한다.

ALPN([ALPN] 참조)은 클라이언트가 연결 설정 중 여러 애플리케이션 프로토콜을 제안할 수 있게 한다. 클라이언트가 핸드셰이크 중 포함하는 전송 매개변수는 클라이언트가 제안하는 모든 애플리케이션 프로토콜에 적용된다. 애플리케이션 프로토콜은 초기 흐름 제어 한도와 같은 전송 매개변수의 값을 권장할 수 있다. 그러나 전송 매개변수 값에 제약을 설정하는 애플리케이션 프로토콜은 이러한 제약이 충돌할 경우 클라이언트가 여러 애플리케이션 프로토콜을 제안하는 것을 불가능하게 만들 수 있다.

7.4.1. 0-RTT를 위한 전송 매개변수 값

0-RTT 사용은 클라이언트와 서버 모두가 이전 연결에서 협상된 프로토콜 매개변수를 사용하는 것에 의존한다. 0-RTT를 활성화하기 위해, 엔드포인트는 연결에서 수신한 모든 세션 티켓과 함께 서버 전송 매개변수의 값을 저장한다. 엔드포인트는 또한 애플리케이션 프로토콜이나 암호화 핸드셰이크에 필요한 모든 정보도 저장한다. Section 4.6 of [QUIC-TLS]를 참조한다. 저장된 전송 매개변수의 값은 세션 티켓을 사용해 0-RTT를 시도할 때 사용된다.

기억된 전송 매개변수는 핸드셰이크가 완료되고 클라이언트가 1-RTT 패킷을 보내기 시작할 때까지 새 연결에 적용된다. 핸드셰이크가 완료되면 클라이언트는 핸드셰이크에서 설정된 전송 매개변수를 사용한다. 일부는 향후 연결에 적용되지 않거나 0-RTT 사용에 영향을 주지 않기 때문에, 모든 전송 매개변수가 기억되는 것은 아니다.

새 전송 매개변수의 정의(Section 7.4.2)는 0-RTT를 위해 전송 매개변수를 저장하는 것이 의무인지, 선택인지, 금지되는지를 명시해야 MUST 한다. 클라이언트는 처리할 수 없는 전송 매개변수를 저장할 필요가 없다.

클라이언트는 다음 매개변수에 대해 기억된 값을 사용해서는 MUST NOT 안 된다: ack_delay_exponent, max_ack_delay, initial_source_connection_id, original_destination_connection_id, preferred_address, retry_source_connection_id, and stateless_reset_token. 클라이언트는 대신 핸드셰이크에서 서버의 새 값을 사용해야 MUST 한다. 서버가 새 값을 제공하지 않으면 기본값이 사용된다.

0-RTT 데이터 전송을 시도하는 클라이언트는 자신이 처리할 수 있는 서버가 사용한 모든 다른 전송 매개변수를 기억해야 MUST 한다. 서버는 이러한 전송 매개변수를 기억하거나, 값의 무결성 보호된 복사본을 티켓에 저장하고 0-RTT 데이터를 수락할 때 그 정보를 복구할 수 있다. 서버는 0-RTT 데이터를 수락할지 결정하는 데 전송 매개변수를 사용한다.

서버가 0-RTT 데이터를 수락하면, 클라이언트가 자신의 0-RTT 데이터로 위반할 수 있는 어떤 한도도 줄이거나 어떤 값도 변경해서는 MUST NOT 안 된다. 특히, 0-RTT 데이터를 수락하는 서버는 다음 매개변수(Section 18.2)에 대해 기억된 매개변수 값보다 작은 값을 설정해서는 MUST NOT 안 된다.

  • active_connection_id_limit
  • initial_max_data
  • initial_max_stream_data_bidi_local
  • initial_max_stream_data_bidi_remote
  • initial_max_stream_data_uni
  • initial_max_streams_bidi
  • initial_max_streams_uni

특정 전송 매개변수를 생략하거나 0 값으로 설정하면 0-RTT 데이터가 활성화되지만 사용할 수 없는 결과가 발생할 수 있다. 애플리케이션 데이터 전송을 허용하는 전송 매개변수의 해당 부분집합은 0-RTT에 대해 0이 아닌 값으로 설정되어야 SHOULD 한다. 여기에는 initial_max_data와, (1) initial_max_streams_bidi 및 initial_max_stream_data_bidi_remote 또는 (2) initial_max_streams_uni 및 initial_max_stream_data_uni가 포함된다.

서버는 클라이언트가 0-RTT를 보낼 때 적용하는 기억된 값보다 더 큰 초기 스트림 흐름 제어 한도를 스트림에 제공할 수 있다. 핸드셰이크가 완료되면, 클라이언트는 initial_max_stream_data_bidi_remote 및 initial_max_stream_data_uni의 업데이트된 값을 사용해 모든 송신 스트림의 흐름 제어 한도를 업데이트한다.

서버는 이전에 보낸 max_idle_timeout, max_udp_payload_size 및 disable_active_migration 매개변수 값을 저장하고 복구할 수 MAY 있으며, 더 작은 값을 선택하면 0-RTT를 거부할 수 있다. 0-RTT 데이터를 수락하면서 이러한 매개변수 값을 낮추면 연결 성능이 저하될 수 있다. 특히 max_udp_payload_size를 낮추면 패킷이 삭제되어 0-RTT 데이터를 바로 거부하는 것과 비교해 성능이 더 나빠질 수 있다.

서버는 복원된 전송 매개변수 값을 지원할 수 없으면 0-RTT 데이터를 거부해야 MUST 한다.

0-RTT 패킷에서 프레임을 보낼 때, 클라이언트는 기억된 전송 매개변수만 사용해야 MUST 한다. 특히, 서버의 업데이트된 전송 매개변수나 1-RTT 패킷에서 수신한 프레임으로부터 알게 된 업데이트된 값을 사용해서는 MUST NOT 안 된다. 핸드셰이크에서 나온 전송 매개변수의 업데이트된 값은 1-RTT 패킷에만 적용된다. 예를 들어, 기억된 전송 매개변수의 흐름 제어 한도는 그 값이 핸드셰이크나 1-RTT 패킷에서 전송된 프레임에 의해 증가하더라도 모든 0-RTT 패킷에 적용된다. 서버는 0-RTT에서 업데이트된 전송 매개변수를 사용하는 것을 PROTOCOL_VIOLATION 유형의 연결 오류로 처리할 수 MAY 있다.

7.4.2. 새 전송 매개변수

새 전송 매개변수는 새 프로토콜 동작을 협상하는 데 사용될 수 있다. 엔드포인트는 자신이 지원하지 않는 전송 매개변수를 무시해야 MUST 한다. 따라서 전송 매개변수가 없으면 해당 매개변수를 사용해 협상되는 모든 선택적 프로토콜 기능이 비활성화된다. Section 18.1에 설명된 것처럼, 이 요구사항을 실행하기 위해 일부 식별자가 예약되어 있다.

전송 매개변수를 이해하지 못하는 클라이언트는 이를 폐기하고 이후 연결에서 0-RTT를 시도할 수 있다. 그러나 클라이언트가 폐기한 전송 매개변수에 대한 지원을 추가하면, 0-RTT를 시도할 때 해당 전송 매개변수가 설정하는 제약을 위반할 위험이 있다. 새 전송 매개변수는 가장 보수적인 값을 기본값으로 설정하여 이 문제를 피할 수 있다. 클라이언트는 현재 지원하지 않는 매개변수까지 포함해 모든 매개변수를 기억함으로써 이 문제를 피할 수 있다.

새 전송 매개변수는 Section 22.3의 규칙에 따라 등록될 수 있다.

7.5. 암호화 메시지 버퍼링

구현은 순서를 벗어나 수신된 CRYPTO 데이터의 버퍼를 유지해야 한다. CRYPTO 프레임에는 흐름 제어가 없기 때문에, 엔드포인트는 잠재적으로 자신의 피어가 제한 없는 양의 데이터를 버퍼링하도록 강제할 수 있다.

구현은 순서를 벗어난 CRYPTO 프레임에서 수신한 데이터 중 최소 4096바이트의 버퍼링을 지원해야 MUST 한다. 엔드포인트는 핸드셰이크 중 더 많은 데이터가 버퍼링되도록 허용할 수 MAY 있다. 핸드셰이크 중 더 큰 한도는 더 큰 키나 자격 증명의 교환을 가능하게 할 수 있다. 엔드포인트의 버퍼 크기는 연결 수명 동안 일정하게 유지될 필요가 없다.

핸드셰이크 중 CRYPTO 프레임을 버퍼링할 수 없으면 연결 실패로 이어질 수 있다. 핸드셰이크 중 엔드포인트의 버퍼가 초과되면, 핸드셰이크를 완료하기 위해 일시적으로 버퍼를 확장할 수 있다. 엔드포인트가 버퍼를 확장하지 않으면, CRYPTO_BUFFER_EXCEEDED 오류 코드로 연결을 닫아야 MUST 한다.

핸드셰이크가 완료된 후 엔드포인트가 CRYPTO 프레임의 모든 데이터를 버퍼링할 수 없으면, 해당 CRYPTO 프레임과 이후에 수신되는 모든 CRYPTO 프레임을 폐기할 수 MAY 있거나, CRYPTO_BUFFER_EXCEEDED 오류 코드로 연결을 닫을 수 MAY 있다. 폐기된 CRYPTO 프레임을 포함하는 패킷은 확인 응답되어야 MUST 한다. CRYPTO 프레임은 폐기되었더라도 해당 패킷은 전송 계층에 의해 수신되고 처리되었기 때문이다.

8. 주소 검증

주소 검증은 엔드포인트가 트래픽 증폭 공격에 사용될 수 없도록 보장한다. 이러한 공격에서는 피해자를 식별하는 스푸핑된 소스 주소 정보가 포함된 패킷이 서버로 전송된다. 서버가 그 패킷에 대한 응답으로 더 많거나 더 큰 패킷을 생성하면, 공격자는 서버를 사용하여 자신이 직접 보낼 수 있는 것보다 더 많은 데이터를 피해자 쪽으로 보낼 수 있다.

증폭 공격에 대한 주된 방어는 피어가 자신이 주장하는 전송 주소에서 패킷을 수신할 수 있음을 검증하는 것이다. 따라서 아직 검증되지 않은 주소에서 패킷을 수신한 후, 엔드포인트는 검증되지 않은 주소로 보내는 데이터 양을 해당 주소에서 수신한 데이터 양의 세 배로 제한해야 MUST 한다. 이 응답 크기 제한은 증폭 방지 한도라고 한다.

주소 검증은 연결 설정 중(Section 8.1 참조)과 연결 마이그레이션 중(Section 8.2 참조)에 모두 수행된다.

8.1. 연결 설정 중 주소 검증

연결 설정은 양쪽 엔드포인트에 대해 암묵적으로 주소 검증을 제공한다. 특히 Handshake 키로 보호된 패킷을 수신했다는 것은 피어가 Initial 패킷을 성공적으로 처리했음을 확인해 준다. 엔드포인트가 피어로부터 Handshake 패킷을 성공적으로 처리하면, 피어 주소가 검증된 것으로 간주할 수 있다.

또한 피어가 엔드포인트가 선택한 연결 ID를 사용하고 그 연결 ID가 최소 64비트의 엔트로피를 포함한다면, 엔드포인트는 피어 주소가 검증된 것으로 간주할 수 MAY 있다.

클라이언트의 경우, 첫 번째 Initial 패킷의 Destination Connection ID 필드 값은 임의의 패킷을 성공적으로 처리하는 과정의 일부로 서버 주소를 검증할 수 있게 한다. 서버의 Initial 패킷은 이 값에서 파생된 키로 보호된다(Section 5.2 of [QUIC-TLS] 참조). 또는 이 값은 서버가 Version Negotiation 패킷(Section 6)에서 에코하거나 Retry 패킷의 Integrity Tag(Section 5.8 of [QUIC-TLS])에 포함된다.

클라이언트 주소를 검증하기 전에, 서버는 자신이 수신한 바이트 수의 세 배보다 많은 바이트를 보내서는 MUST NOT 안 된다. 이는 스푸핑된 소스 주소를 사용하여 수행될 수 있는 모든 증폭 공격의 규모를 제한한다. 주소 검증 전에 증폭을 피하기 위해, 서버는 단일 연결에 고유하게 귀속되는 데이터그램에서 수신한 모든 페이로드 바이트를 계산해야 MUST 한다. 여기에는 성공적으로 처리된 패킷을 포함하는 데이터그램과 모든 패킷이 폐기되는 데이터그램이 포함된다.

클라이언트는 Initial 패킷을 포함하는 UDP 데이터그램의 UDP 페이로드가 최소 1200바이트가 되도록 보장해야 MUST 하며, 필요하다면 PADDING 프레임을 추가한다. 패딩된 데이터그램을 보내는 클라이언트는 서버가 주소 검증을 완료하기 전에 더 많은 데이터를 보낼 수 있게 한다.

클라이언트가 추가 Initial 또는 Handshake 패킷을 보내지 않으면, 서버의 Initial 또는 Handshake 패킷 손실이 교착 상태를 일으킬 수 있다. 서버가 증폭 방지 한도에 도달했고 클라이언트가 자신이 보낸 모든 데이터에 대한 확인 응답을 수신한 경우 교착 상태가 발생할 수 있다. 이 경우 클라이언트가 추가 패킷을 보낼 이유가 없으면, 서버는 클라이언트 주소를 검증하지 못했기 때문에 더 많은 데이터를 보낼 수 없게 된다. 이 교착 상태를 방지하기 위해, 클라이언트는 Probe Timeout(PTO)에서 패킷을 보내야 MUST 한다. Section 6.2 of [QUIC-RECOVERY]를 참조한다. 구체적으로, 클라이언트는 Handshake 키가 없으면 최소 1200바이트를 포함하는 UDP 데이터그램에 Initial 패킷을 보내야 MUST 하며, 그렇지 않으면 Handshake 패킷을 보내야 한다.

서버는 암호화 핸드셰이크를 시작하기 전에 클라이언트 주소를 검증하고 싶을 수 있다. QUIC는 핸드셰이크를 완료하기 전에 주소 검증을 제공하기 위해 Initial 패킷의 토큰을 사용한다. 이 토큰은 연결 설정 중 Retry 패킷(Section 8.1.2 참조)을 통해 또는 이전 연결에서 NEW_TOKEN 프레임(Section 8.1.3 참조)을 사용하여 클라이언트에게 전달된다.

주소 검증 전에 부과되는 전송 한도 외에도, 서버는 혼잡 제어기가 설정한 한도에 의해 무엇을 보낼 수 있는지도 제한된다. 클라이언트는 혼잡 제어기에 의해서만 제한된다.

8.1.1. 토큰 구성

NEW_TOKEN 프레임 또는 Retry 패킷으로 전송되는 토큰은 서버가 해당 토큰이 클라이언트에게 어떻게 제공되었는지 식별할 수 있는 방식으로 구성되어야 MUST 한다. 이러한 토큰은 같은 필드에 운반되지만 서버에서 서로 다른 처리를 요구한다.

8.1.2. Retry 패킷을 사용한 주소 검증

클라이언트의 Initial 패킷을 수신하면, 서버는 토큰을 포함하는 Retry 패킷(Section 17.2.5)을 보내 주소 검증을 요청할 수 있다. 이 토큰은 클라이언트가 Retry 패킷을 수신한 후 해당 연결을 위해 보내는 모든 Initial 패킷에서 반복되어야 MUST 한다.

Retry 패킷에서 제공된 토큰을 포함하는 Initial 패킷을 처리한 것에 대한 응답으로, 서버는 또 다른 Retry 패킷을 보낼 수 없다. 서버는 연결을 거부하거나 진행을 허용할 수만 있다.

공격자가 자신의 주소에 대해 유효한 토큰을 생성할 수 없고 (Section 8.1.4 참조), 클라이언트가 그 토큰을 반환할 수 있는 한, 이는 클라이언트가 토큰을 수신했음을 서버에 증명한다.

서버는 또한 Retry 패킷을 사용해 연결 설정의 상태 및 처리 비용을 지연시킬 수 있다. Section 18.2에 정의된 original_destination_connection_id 전송 매개변수와 함께 서버가 다른 연결 ID를 제공하도록 요구하면, 서버 또는 서버와 협력하는 엔티티가 클라이언트로부터 원래 Initial 패킷을 수신했음을 증명하도록 강제한다. 다른 연결 ID를 제공하면 서버가 후속 패킷이 라우팅되는 방식에 대해 어느 정도 제어권도 갖게 된다. 이는 연결을 다른 서버 인스턴스로 전달하는 데 사용될 수 있다.

서버가 유효하지 않은 Retry 토큰을 포함하지만 그 외에는 유효한 클라이언트 Initial을 수신하면, 서버는 클라이언트가 또 다른 Retry 토큰을 수락하지 않을 것임을 안다. 서버는 이러한 패킷을 폐기하고 클라이언트가 타임아웃을 통해 핸드셰이크 실패를 감지하도록 할 수 있지만, 이는 클라이언트에 상당한 지연 패널티를 부과할 수 있다. 대신 서버는 INVALID_TOKEN 오류로 연결을 즉시 닫아야 SHOULD 한다(Section 10.2). 이 시점에서 서버는 연결에 대한 어떠한 상태도 설정하지 않았으므로 closing 기간에 들어가지 않는다는 점에 유의한다.

Retry 패킷 사용을 보여주는 흐름은 Figure 9에 표시되어 있다.

Client                                                  Server

Initial[0]: CRYPTO[CH] ->

                                                <- Retry+Token

Initial+Token[1]: CRYPTO[CH] ->

                                 Initial[0]: CRYPTO[SH] ACK[1]
                       Handshake[0]: CRYPTO[EE, CERT, CV, FIN]
                                 <- 1-RTT[0]: STREAM[1, "..."]
Figure 9: Retry가 있는 예시 핸드셰이크

8.1.3. 향후 연결을 위한 주소 검증

서버는 한 연결 중 클라이언트에게 이후 연결에서 사용할 수 있는 주소 검증 토큰을 제공할 수 MAY 있다. 주소 검증은 0-RTT에서 특히 중요하다. 서버가 0-RTT 데이터에 대한 응답으로 클라이언트에게 상당한 양의 데이터를 보낼 수 있기 때문이다.

서버는 NEW_TOKEN 프레임(Section 19.7)을 사용하여 향후 연결을 검증하는 데 사용할 수 있는 주소 검증 토큰을 클라이언트에게 제공한다. 이후 연결에서 클라이언트는 주소 검증을 제공하기 위해 이 토큰을 Initial 패킷에 포함한다. Retry가 토큰을 더 새로운 토큰으로 대체하지 않는 한, 클라이언트는 자신이 보내는 모든 Initial 패킷에 토큰을 포함해야 MUST 한다. 클라이언트는 Retry에서 제공된 토큰을 향후 연결에 사용해서는 MUST NOT 안 된다. 서버는 예상된 토큰을 운반하지 않는 모든 Initial 패킷을 폐기할 수 MAY 있다.

즉시 사용되는 Retry 패킷용으로 생성되는 토큰과 달리, NEW_TOKEN 프레임으로 전송된 토큰은 일정 시간이 지난 후에도 사용할 수 있다. 따라서 토큰은 만료 시간을 가져야 SHOULD 하며, 이는 명시적 만료 시간이거나 만료 시간을 동적으로 계산하는 데 사용할 수 있는 발급 타임스탬프일 수 있다. 서버는 만료 시간을 저장하거나 암호화된 형태로 토큰에 포함할 수 있다.

NEW_TOKEN으로 발급된 토큰은 관찰자가 그 값들을 토큰이 발급된 연결과 연결할 수 있게 하는 정보를 포함해서는 MUST NOT 안 된다. 예를 들어 값들이 암호화되지 않는 한, 이전 연결 ID나 주소 지정 정보를 포함할 수 없다. 서버는 손실된 이전 NEW_TOKEN 프레임을 복구하기 위해 전송되는 경우를 제외하고, 자신이 보내는 모든 NEW_TOKEN 프레임이 모든 클라이언트에 걸쳐 고유하도록 보장해야 MUST 한다. 서버가 Retry의 토큰과 NEW_TOKEN의 토큰을 구분할 수 있게 하는 정보는 서버 이외의 엔티티가 접근할 수 MAY 있다.

서로 다른 두 연결에서 클라이언트 포트 번호가 같을 가능성은 낮다. 따라서 포트 검증은 성공할 가능성이 낮다.

NEW_TOKEN 프레임에서 수신한 토큰은 해당 연결이 권한이 있다고 간주되는 모든 서버(예: 인증서에 포함된 서버 이름)에 적용된다. 클라이언트가 적용 가능하고 사용되지 않은 토큰을 보유하고 있는 서버에 연결할 때, 클라이언트는 자신의 Initial 패킷의 Token 필드에 그 토큰을 포함해야 SHOULD 한다. 토큰을 포함하면 추가 왕복 없이 서버가 클라이언트 주소를 검증할 수 있다. 클라이언트는 토큰을 발급한 서버와 연결하려는 서버가 토큰을 공동으로 관리한다는 지식이 없는 한, 자신이 연결하려는 서버에 적용되지 않는 토큰을 포함해서는 MUST NOT 안 된다. 클라이언트는 그 서버에 대한 이전 연결에서 얻은 토큰을 사용할 수 MAY 있다.

토큰은 서버가 토큰이 발급된 연결과 토큰이 사용되는 모든 연결 사이의 활동을 상관시킬 수 있게 한다. 서버와의 식별 연속성을 끊고 싶은 클라이언트는 NEW_TOKEN 프레임으로 제공된 토큰을 폐기할 수 있다. 이에 비해 Retry 패킷에서 얻은 토큰은 연결 시도 중 즉시 사용되어야 MUST 하며, 이후 연결 시도에서 사용할 수 없다.

클라이언트는 서로 다른 연결 시도에 NEW_TOKEN 프레임의 토큰을 재사용해서는 SHOULD NOT 안 된다. 토큰을 재사용하면 네트워크 경로상의 엔티티가 연결들을 연결시킬 수 있다. Section 9.5를 참조한다.

클라이언트는 단일 연결에서 여러 토큰을 수신할 수 있다. 연결 가능성을 방지하는 것을 제외하면, 어떤 토큰이든 어떤 연결 시도에도 사용할 수 있다. 서버는 여러 연결 시도에 대한 주소 검증을 가능하게 하거나 유효하지 않게 될 수 있는 오래된 토큰을 대체하기 위해 추가 토큰을 보낼 수 있다. 클라이언트에게 이러한 모호성은 가장 최근의 사용되지 않은 토큰을 보내는 것이 가장 효과적일 가능성이 높다는 것을 의미한다. 오래된 토큰을 저장하고 사용해도 부정적인 결과는 없지만, 클라이언트는 오래된 토큰이 서버의 주소 검증에 덜 유용할 가능성이 있다고 간주할 수 있다.

서버가 주소 검증 토큰이 포함된 Initial 패킷을 수신하면, 이미 주소 검증을 완료하지 않은 한, 토큰 검증을 시도해야 MUST 한다. 토큰이 유효하지 않으면, 서버는 Retry 패킷을 보낼 가능성을 포함하여 클라이언트가 검증된 주소를 갖지 않은 것처럼 진행해야 SHOULD 한다. NEW_TOKEN 프레임과 Retry 패킷으로 제공된 토큰은 서버가 구분할 수 있으며(Section 8.1.1 참조), 후자는 더 엄격하게 검증될 수 있다. 검증이 성공하면, 서버는 핸드셰이크가 진행되도록 허용해야 SHOULD 한다.

상태 없는 설계에서, 서버는 암호화되고 인증된 토큰을 사용해 클라이언트에게 정보를 전달하고, 나중에 서버가 이를 복구하여 클라이언트 주소를 검증하는 데 사용할 수 있다. 토큰은 암호화 핸드셰이크에 통합되지 않으므로 인증되지 않는다. 예를 들어, 클라이언트는 토큰을 재사용할 수 있다. 이 속성을 악용하는 공격을 피하기 위해, 서버는 토큰 사용을 클라이언트 주소를 검증하는 데 필요한 정보로만 제한할 수 있다.

클라이언트는 한 연결에서 얻은 토큰을 같은 버전을 사용하는 모든 연결 시도에 사용할 수 MAY 있다. 사용할 토큰을 선택할 때 클라이언트는 가능한 애플리케이션 프로토콜 선택, 세션 티켓 또는 기타 연결 속성을 포함하여 시도 중인 연결의 다른 속성을 고려할 필요가 없다.

8.1.4. 주소 검증 토큰 무결성

주소 검증 토큰은 추측하기 어려워야 MUST 한다. 토큰에 최소 128비트의 엔트로피를 가진 임의 값을 포함하면 충분하지만, 이는 서버가 클라이언트에게 보낸 값을 기억하는 것에 의존한다.

토큰 기반 방식은 서버가 검증과 관련된 모든 상태를 클라이언트에게 오프로드할 수 있게 한다. 이 설계가 작동하려면, 토큰은 클라이언트에 의한 수정이나 위조에 대해 무결성 보호로 보호되어야 MUST 한다. 무결성 보호가 없으면 악의적인 클라이언트가 서버에 의해 수락될 토큰 값을 생성하거나 추측할 수 있다. 토큰에 대한 무결성 보호 키에는 서버만 접근할 필요가 있다.

토큰에는 단일하게 잘 정의된 형식이 필요하지 않다. 토큰을 생성하는 서버가 그 토큰을 소비하기 때문이다. Retry 패킷으로 전송되는 토큰은 서버가 클라이언트 패킷의 소스 IP 주소와 포트가 일정하게 유지되는지 검증할 수 있는 정보를 포함해야 SHOULD 한다.

NEW_TOKEN 프레임으로 전송되는 토큰은 서버가 토큰이 발급된 시점 이후 클라이언트 IP 주소가 변경되지 않았음을 검증할 수 있는 정보를 포함해야 MUST 한다. 클라이언트 주소가 변경된 경우에도 서버는 Retry 패킷을 보내지 않기로 결정할 때 NEW_TOKEN 프레임의 토큰을 사용할 수 있다. 클라이언트 IP 주소가 변경되었다면, 서버는 증폭 방지 한도를 따라야 MUST 한다. Section 8을 참조한다. NAT가 있는 경우 이 요구사항은 NAT를 공유하는 다른 호스트를 증폭 공격으로부터 보호하기에 충분하지 않을 수 있음에 유의한다.

공격자는 DDoS 공격에서 서버를 증폭기로 사용하기 위해 토큰을 재생할 수 있다. 이러한 공격으로부터 보호하기 위해, 서버는 토큰 재생이 방지되거나 제한되도록 보장해야 MUST 한다. 서버는 Retry 패킷으로 전송된 토큰이 클라이언트가 즉시 반환하는 것이므로 짧은 시간 동안만 수락되도록 보장해야 SHOULD 한다. NEW_TOKEN 프레임(Section 19.7)으로 제공된 토큰은 더 오래 유효해야 하지만 여러 번 수락되어서는 SHOULD NOT 안 된다. 서버는 가능하다면 토큰을 한 번만 사용하도록 허용하는 것이 권장된다. 토큰은 적용 가능성이나 재사용을 더 좁히기 위해 클라이언트에 대한 추가 정보를 포함할 수 MAY 있다.

8.2. 경로 검증

경로 검증은 연결 마이그레이션 중(Section 9 참조) 주소 변경 후 도달 가능성을 검증하기 위해 양쪽 피어가 사용한다. 경로 검증에서 엔드포인트는 특정 로컬 주소와 특정 피어 주소 사이의 도달 가능성을 테스트한다. 여기서 주소는 IP 주소와 포트의 2-튜플이다.

경로 검증은 피어로 향하는 경로에서 보낸 패킷이 그 피어에 의해 수신되는지 테스트한다. 경로 검증은 마이그레이션하는 피어로부터 수신된 패킷이 스푸핑된 소스 주소를 운반하지 않도록 보장하는 데 사용된다.

경로 검증은 피어가 반환 방향으로 보낼 수 있는지를 검증하지 않는다. 확인 응답은 엔트로피가 충분하지 않고 스푸핑될 수 있으므로 반환 경로 검증에 사용할 수 없다. 엔드포인트는 경로의 각 방향에 대한 도달 가능성을 독립적으로 결정하므로, 반환 도달 가능성은 피어에 의해서만 설정될 수 있다.

경로 검증은 어느 엔드포인트든 언제든 사용할 수 있다. 예를 들어, 엔드포인트는 비활성 기간 이후 피어가 여전히 자신의 주소를 보유하고 있는지 확인할 수 있다.

경로 검증은 NAT 통과 메커니즘으로 설계되지 않았다. 여기에 설명된 메커니즘이 NAT 통과를 지원하는 NAT 바인딩을 생성하는 데 효과적일 수는 있지만, 한 엔드포인트가 해당 경로에서 먼저 패킷을 보내지 않고도 패킷을 수신할 수 있다는 것을 전제로 한다. 효과적인 NAT 통과에는 여기에서 제공되지 않는 추가 동기화 메커니즘이 필요하다.

엔드포인트는 경로 검증에 사용되는 PATH_CHALLENGE 및 PATH_RESPONSE 프레임과 함께 다른 프레임을 포함할 수 MAY 있다. 특히 엔드포인트는 Path Maximum Transmission Unit Discovery(PMTUD)를 위해 PATH_CHALLENGE 프레임과 함께 PADDING 프레임을 포함할 수 있다. Section 14.2.1을 참조한다. 엔드포인트는 PATH_RESPONSE 프레임을 보낼 때 자신의 PATH_CHALLENGE 프레임도 포함할 수 있다.

엔드포인트는 새 로컬 주소에서 전송되는 프로브에 새 연결 ID를 사용한다. Section 9.5를 참조한다. 새 경로를 탐색할 때, 엔드포인트는 피어가 응답에 사용할 미사용 연결 ID를 사용할 수 있도록 보장할 수 있다. 피어의 active_connection_id_limit가 허용한다면, 같은 패킷에 NEW_CONNECTION_ID 및 PATH_CHALLENGE 프레임을 보내면 피어가 응답을 보낼 때 미사용 연결 ID를 사용할 수 있도록 보장된다.

엔드포인트는 여러 경로를 동시에 탐색하기로 선택할 수 있다. 프로브에 사용되는 동시 경로 수는 피어가 이전에 제공한 추가 연결 ID 수에 의해 제한된다. 프로브에 사용되는 각 새 로컬 주소에는 이전에 사용되지 않은 연결 ID가 필요하기 때문이다.

8.2.1. 경로 검증 시작

경로 검증을 시작하기 위해, 엔드포인트는 검증할 경로에서 예측 불가능한 페이로드를 포함하는 PATH_CHALLENGE 프레임을 보낸다.

엔드포인트는 패킷 손실에 대비하기 위해 여러 PATH_CHALLENGE 프레임을 보낼 수 MAY 있다. 그러나 엔드포인트는 단일 패킷에 여러 PATH_CHALLENGE 프레임을 보내서는 SHOULD NOT 안 된다.

엔드포인트는 Initial 패킷을 보내는 것보다 더 자주 PATH_CHALLENGE 프레임을 포함하는 패킷으로 새 경로를 탐색해서는 SHOULD NOT 안 된다. 이는 연결 마이그레이션이 새 연결을 설정하는 것보다 새 경로에 더 많은 부하를 주지 않도록 보장한다.

엔드포인트는 피어의 응답을 해당 PATH_CHALLENGE와 연관시킬 수 있도록 모든 PATH_CHALLENGE 프레임에 예측 불가능한 데이터를 사용해야 MUST 한다.

엔드포인트는 경로의 증폭 방지 한도가 이 크기의 데이터그램 전송을 허용하지 않는 경우를 제외하고, PATH_CHALLENGE 프레임을 포함하는 데이터그램을 허용되는 가장 작은 최대 데이터그램 크기인 최소 1200바이트로 확장해야 MUST 한다. 이 크기의 UDP 데이터그램을 보내면 엔드포인트에서 피어로 가는 네트워크 경로를 QUIC에 사용할 수 있음을 보장한다. Section 14를 참조한다.

증폭 방지 한도 때문에 엔드포인트가 데이터그램 크기를 1200바이트로 확장할 수 없는 경우, 경로 MTU는 검증되지 않는다. 경로 MTU가 충분히 크도록 보장하기 위해, 엔드포인트는 최소 1200바이트의 데이터그램에 PATH_CHALLENGE 프레임을 보내 두 번째 경로 검증을 수행해야 MUST 한다. 이 추가 검증은 PATH_RESPONSE를 성공적으로 수신한 후 또는 더 큰 데이터그램을 보내도 증폭 방지 한도를 초과하지 않을 만큼 충분한 바이트가 경로에서 수신되었을 때 수행할 수 있다.

데이터그램이 확장되는 다른 경우와 달리, 엔드포인트는 PATH_CHALLENGE 또는 PATH_RESPONSE를 포함하는 경우 너무 작아 보이는 데이터그램을 폐기해서는 MUST NOT 안 된다.

8.2.2. 경로 검증 응답

PATH_CHALLENGE 프레임을 수신하면, 엔드포인트는 PATH_CHALLENGE 프레임에 포함된 데이터를 PATH_RESPONSE 프레임에 에코하여 응답해야 MUST 한다. 엔드포인트는 혼잡 제어에 의해 제한되지 않는 한 PATH_RESPONSE 프레임을 포함하는 패킷의 전송을 지연해서는 MUST NOT 안 된다.

PATH_RESPONSE 프레임은 PATH_CHALLENGE 프레임이 수신된 네트워크 경로에서 전송되어야 MUST 한다. 이는 경로가 양방향으로 작동하는 경우에만 피어의 경로 검증이 성공하도록 보장한다. 이 요구사항은 경로 검증을 시작한 엔드포인트에 의해 강제되어서는 MUST NOT 안 된다. 그렇게 하면 마이그레이션에 대한 공격이 가능해지기 때문이다. Section 9.3.3을 참조한다.

엔드포인트는 PATH_RESPONSE 프레임을 포함하는 데이터그램을 허용되는 가장 작은 최대 데이터그램 크기인 최소 1200바이트로 확장해야 MUST 한다. 이는 경로가 이 크기의 데이터그램을 양방향으로 운반할 수 있음을 검증한다. 그러나 결과 데이터가 증폭 방지 한도를 초과하는 경우, 엔드포인트는 PATH_RESPONSE를 포함하는 데이터그램을 확장해서는 MUST NOT 안 된다. 이는 수신된 PATH_CHALLENGE가 확장된 데이터그램으로 전송되지 않았을 때만 발생할 것으로 예상된다.

엔드포인트는 하나의 PATH_CHALLENGE 프레임에 대한 응답으로 둘 이상의 PATH_RESPONSE 프레임을 보내서는 MUST NOT 안 된다. Section 13.3을 참조한다. 피어는 추가 PATH_RESPONSE 프레임을 유도하기 위해 필요에 따라 더 많은 PATH_CHALLENGE 프레임을 보낼 것으로 예상된다.

8.2.3. 성공적인 경로 검증

이전에 PATH_CHALLENGE 프레임으로 보낸 데이터를 포함하는 PATH_RESPONSE 프레임을 수신하면 경로 검증이 성공한다. 어떤 네트워크 경로에서 수신된 PATH_RESPONSE 프레임이든 PATH_CHALLENGE가 전송된 경로를 검증한다.

엔드포인트가 최소 1200바이트로 확장되지 않은 데이터그램에 PATH_CHALLENGE 프레임을 보내고, 이에 대한 응답이 피어 주소를 검증한다면, 경로는 검증되지만 경로 MTU는 검증되지 않는다. 그 결과 엔드포인트는 이제 수신한 데이터 양의 세 배를 초과하여 보낼 수 있다. 그러나 엔드포인트는 경로가 필요한 MTU를 지원하는지 확인하기 위해 확장된 데이터그램으로 또 다른 경로 검증을 시작해야 MUST 한다.

PATH_CHALLENGE 프레임을 포함하는 패킷에 대한 확인 응답 수신은 충분한 검증이 아니다. 확인 응답은 악의적인 피어에 의해 스푸핑될 수 있기 때문이다.

8.2.4. 실패한 경로 검증

경로 검증은 경로를 검증하려는 엔드포인트가 검증 시도를 포기할 때에만 실패한다.

엔드포인트는 타이머를 기준으로 경로 검증을 포기해야 SHOULD 한다. 이 타이머를 설정할 때, 구현은 새 경로의 왕복 시간이 원래 경로보다 길 수 있음을 주의해야 한다. 현재 PTO와 새 경로의 PTO ([QUIC-RECOVERY]에 정의된 kInitialRtt 사용) 중 더 큰 값의 세 배가 RECOMMENDED 된다.

이 타임아웃은 경로 검증 실패 전에 여러 PTO가 만료될 수 있게 하여, 단일 PATH_CHALLENGE 또는 PATH_RESPONSE 프레임의 손실이 경로 검증 실패를 일으키지 않도록 한다.

엔드포인트가 새 경로에서 다른 프레임을 포함하는 패킷을 수신할 수 있지만, 경로 검증이 성공하려면 적절한 데이터를 가진 PATH_RESPONSE 프레임이 필요하다는 점에 유의한다.

엔드포인트가 경로 검증을 포기하면, 해당 경로를 사용할 수 없다고 판단한다. 이것이 반드시 연결 실패를 의미하지는 않는다. 엔드포인트는 적절한 경우 다른 경로를 통해 패킷을 계속 보낼 수 있다. 사용 가능한 경로가 없으면 엔드포인트는 새 경로가 사용 가능해질 때까지 기다리거나 연결을 닫을 수 있다. 피어로 향하는 유효한 네트워크 경로가 없는 엔드포인트는 NO_VIABLE_PATH 연결 오류를 사용해 이를 신호할 수 MAY 있다. 단, 이는 네트워크 경로가 존재하지만 필요한 MTU(Section 14)를 지원하지 않는 경우에만 가능하다는 점에 유의한다.

경로 검증은 실패 이외의 다른 이유로도 포기될 수 있다. 주로 이는 이전 경로에서 경로 검증이 진행 중일 때 새 경로로 연결 마이그레이션이 시작되는 경우 발생한다.

9. 연결 마이그레이션

연결 ID의 사용은 엔드포인트가 새 네트워크로 마이그레이션하는 경우와 같이 엔드포인트 주소(IP 주소 및 포트)가 변경되어도 연결이 지속될 수 있게 한다. 이 섹션은 엔드포인트가 새 주소로 마이그레이션하는 과정을 설명한다.

QUIC의 설계는 엔드포인트가 핸드셰이크 기간 동안 안정적인 주소를 유지하는 것에 의존한다. 엔드포인트는 Section 4.1.2 of [QUIC-TLS]에 정의된 대로 핸드셰이크가 확인되기 전에는 연결 마이그레이션을 시작해서는 MUST NOT 안 된다.

피어가 disable_active_migration 전송 매개변수를 보낸 경우, 엔드포인트는 피어의 preferred_address 전송 매개변수에 따라 조치한 경우를 제외하고, 피어가 핸드셰이크 중 사용한 주소로 다른 로컬 주소에서 패킷(프로빙 패킷 포함, Section 9.1 참조)을 보내서도 MUST NOT 안 된다. 피어가 이 요구사항을 위반하면, 엔드포인트는 Stateless Reset을 생성하지 않고 해당 경로의 들어오는 패킷을 버리거나, 경로 검증을 진행하고 피어가 마이그레이션하도록 허용해야 MUST 한다. Stateless Reset을 생성하거나 연결을 닫으면, 네트워크의 제3자가 관찰된 트래픽을 스푸핑하거나 조작하여 연결을 닫게 할 수 있다.

피어 주소의 모든 변경이 의도적이거나 능동적인 마이그레이션은 아니다. 피어는 NAT 리바인딩을 경험할 수 있다. 이는 일반적으로 NAT인 미들박스가 흐름에 대해 새 발신 포트 또는 새 발신 IP 주소까지 할당하여 주소가 변경되는 것이다. 엔드포인트는 피어 주소의 변경을 감지하면, 해당 주소를 이전에 검증하지 않은 한 경로 검증(Section 8.2)을 수행해야 MUST 한다.

엔드포인트가 패킷을 보낼 수 있는 검증된 경로를 갖지 않는 경우, 연결 상태를 폐기할 수 MAY 있다. 연결 마이그레이션이 가능한 엔드포인트는 연결 상태를 폐기하기 전에 새 경로가 사용 가능해질 때까지 기다릴 수 MAY 있다.

이 문서는 Section 9.6에 설명된 경우를 제외하고, 연결의 마이그레이션을 새 클라이언트 주소로 제한한다. 클라이언트는 모든 마이그레이션을 시작할 책임이 있다. 서버는 해당 주소에서 비프로빙 패킷을 보기 전까지 클라이언트 주소로 비프로빙 패킷(Section 9.1 참조)을 보내지 않는다. 클라이언트가 알 수 없는 서버 주소에서 패킷을 수신하면, 클라이언트는 이러한 패킷을 폐기해야 MUST 한다.

9.1. 새 경로 탐색

엔드포인트는 연결을 새 로컬 주소로 마이그레이션하기 전에 경로 검증(Section 8.2)을 사용하여 새 로컬 주소에서 피어 도달 가능성을 탐색할 수 MAY 있다. 경로 검증 실패는 단순히 새 경로가 이 연결에 사용할 수 없음을 의미한다. 유효한 대체 경로가 없는 경우를 제외하고, 경로 검증 실패는 연결 종료를 초래하지 않는다.

PATH_CHALLENGE, PATH_RESPONSE, NEW_CONNECTION_ID 및 PADDING 프레임은 "프로빙 프레임"이고, 그 밖의 모든 프레임은 "비프로빙 프레임"이다. 프로빙 프레임만 포함하는 패킷은 "프로빙 패킷"이고, 다른 어떤 프레임이라도 포함하는 패킷은 "비프로빙 패킷"이다.

9.2. 연결 마이그레이션 시작

엔드포인트는 새 로컬 주소에서 비프로빙 프레임을 포함하는 패킷을 보내 연결을 새 로컬 주소로 마이그레이션할 수 있다.

각 엔드포인트는 연결 설정 중 피어의 주소를 검증한다. 따라서 마이그레이션하는 엔드포인트는 피어가 피어의 현재 주소에서 수신할 의향이 있음을 알고 피어에게 보낼 수 있다. 따라서 엔드포인트는 먼저 피어의 주소를 검증하지 않고도 새 로컬 주소로 마이그레이션할 수 있다.

새 경로에서 도달 가능성을 설정하기 위해, 엔드포인트는 새 경로에서 경로 검증(Section 8.2)을 시작한다. 엔드포인트는 피어가 새 주소로 다음 비프로빙 프레임을 보낸 후까지 경로 검증을 지연할 수 MAY 있다.

마이그레이션할 때 새 경로는 엔드포인트의 현재 전송 속도를 지원하지 않을 수 있다. 따라서 엔드포인트는 Section 9.4에 설명된 대로 혼잡 제어기와 RTT 추정치를 재설정한다.

새 경로는 같은 ECN 기능을 갖지 않을 수 있다. 따라서 엔드포인트는 Section 13.4에 설명된 대로 ECN 기능을 검증한다.

9.3. 연결 마이그레이션에 응답하기

새 피어 주소에서 비프로빙 프레임을 포함하는 패킷을 수신하면, 피어가 해당 주소로 마이그레이션했음을 나타낸다.

수신자가 마이그레이션을 허용하는 경우, 이후 패킷을 새 피어 주소로 보내야 MUST 하며, 검증이 이미 진행 중이 아니라면 피어가 그 주소를 소유하고 있음을 검증하기 위해 경로 검증(Section 8.2)을 시작해야 MUST 한다. 수신자가 피어로부터 미사용 연결 ID를 갖고 있지 않다면, 피어가 하나를 제공할 때까지 새 경로에서 아무것도 보낼 수 없다. Section 9.5를 참조한다.

엔드포인트는 가장 큰 번호의 비프로빙 패킷에 대한 응답으로만 패킷을 보낼 주소를 변경한다. 이는 엔드포인트가 재정렬된 패킷을 수신하는 경우 이전 피어 주소로 패킷을 보내지 않도록 보장한다.

엔드포인트는 검증되지 않은 피어 주소로 데이터를 보낼 수 MAY 있지만, Sections 9.3.19.3.2에 설명된 잠재적 공격으로부터 보호해야 MUST 한다. 엔드포인트는 해당 주소가 최근에 관찰된 경우 피어 주소 검증을 생략할 수 MAY 있다. 특히 엔드포인트가 어떤 형태의 허위 마이그레이션을 감지한 뒤 이전에 검증된 경로로 돌아가는 경우, 주소 검증을 생략하고 손실 감지 및 혼잡 상태를 복원하면 공격의 성능 영향을 줄일 수 있다.

비프로빙 패킷을 보낼 주소를 변경한 후, 엔드포인트는 다른 주소에 대한 모든 경로 검증을 포기할 수 있다.

새 피어 주소에서 패킷을 수신하는 것은 피어에서 NAT 리바인딩이 발생한 결과일 수 있다.

새 클라이언트 주소를 검증한 후, 서버는 클라이언트에게 새 주소 검증 토큰(Section 8)을 보내야 SHOULD 한다.

9.3.1. 피어 주소 스푸핑

피어가 엔드포인트가 원하지 않는 호스트에게 과도한 양의 데이터를 보내게 하기 위해 자신의 소스 주소를 스푸핑하고 있을 가능성이 있다. 엔드포인트가 스푸핑하는 피어보다 훨씬 많은 데이터를 보내면, 연결 마이그레이션은 공격자가 피해자 쪽으로 생성할 수 있는 데이터 양을 증폭하는 데 사용될 수 있다.

Section 9.3에 설명된 것처럼, 엔드포인트는 피어의 새 주소 소유를 확인하기 위해 피어의 새 주소를 검증해야 한다. 피어 주소가 유효한 것으로 간주될 때까지, 엔드포인트는 해당 주소로 보내는 데이터 양을 제한한다. Section 8을 참조한다. 이 한도가 없으면, 엔드포인트는 무고한 피해자에 대한 서비스 거부 공격에 사용될 위험이 있다.

엔드포인트가 위에 설명된 대로 피어 주소 검증을 생략하는 경우, 전송 속도를 제한할 필요가 없다.

9.3.2. 경로상 주소 스푸핑

경로상 공격자는 스푸핑된 주소가 포함된 패킷을 복사하고 전달하여 원본 패킷보다 먼저 도착하게 함으로써 허위 연결 마이그레이션을 일으킬 수 있다. 스푸핑된 주소가 포함된 패킷은 마이그레이션하는 연결에서 온 것으로 보이고, 원본 패킷은 중복으로 보이며 삭제된다. 허위 마이그레이션 이후에는, 해당 소스 주소의 엔티티가 원하더라도 자신에게 전송된 PATH_CHALLENGE 프레임을 읽거나 응답하는 데 필요한 암호화 키를 갖지 않으므로 소스 주소 검증이 실패한다.

그러한 허위 마이그레이션으로 인해 연결이 실패하지 않도록 보호하기 위해, 엔드포인트는 새 피어 주소 검증이 실패하면 마지막으로 검증된 피어 주소를 다시 사용해야 MUST 한다. 또한 정당한 피어 주소에서 더 큰 패킷 번호를 가진 패킷을 수신하면 또 다른 연결 마이그레이션이 트리거된다. 이는 허위 마이그레이션 주소의 검증을 포기하게 하여, 공격자가 단일 패킷을 주입하여 시작한 마이그레이션을 제한한다.

엔드포인트가 마지막으로 검증된 피어 주소에 대한 상태를 갖고 있지 않으면, 모든 연결 상태를 폐기하여 연결을 조용히 닫아야 MUST 한다. 그 결과 연결의 새 패킷은 일반적으로 처리된다. 예를 들어, 엔드포인트는 이후 들어오는 모든 패킷에 대한 응답으로 Stateless Reset을 보낼 수 MAY 있다.

9.3.3. 경로 외부 패킷 전달

패킷을 관찰할 수 있는 경로 외부 공격자는 진짜 패킷의 복사본을 엔드포인트로 전달할 수 있다. 복사된 패킷이 진짜 패킷보다 먼저 도착하면, 이는 NAT 리바인딩처럼 보인다. 진짜 패킷은 중복으로 폐기된다. 공격자가 패킷 전달을 계속할 수 있다면, 공격자를 경유하는 경로로 마이그레이션을 일으킬 수 있다. 이는 공격자를 경로상에 위치시켜 이후 모든 패킷을 관찰하거나 삭제할 수 있게 한다.

이 유형의 공격은 공격자가 엔드포인트 사이의 직접 경로와 거의 같은 특성을 가진 경로를 사용하는 것에 의존한다. 비교적 적은 패킷이 전송되거나 패킷 손실이 공격 시도와 겹치는 경우 공격은 더 신뢰성 있게 수행된다.

수신된 최대 패킷 번호를 증가시키는 비프로빙 패킷이 원래 경로에서 수신되면, 엔드포인트는 해당 경로로 돌아간다. 이 경로에서 패킷을 유도하면 공격이 실패할 가능성이 커진다. 따라서 이 공격의 완화는 패킷 교환을 트리거하는 것에 의존한다.

겉보기 마이그레이션에 대한 응답으로, 엔드포인트는 PATH_CHALLENGE 프레임을 사용하여 이전 활성 경로를 검증해야 MUST 한다. 이는 해당 경로에서 새 패킷 전송을 유도한다. 경로가 더 이상 유효하지 않으면 검증 시도는 타임아웃되어 실패한다. 경로가 유효하지만 더 이상 원하지 않는 경우, 검증은 성공하지만 해당 경로에서 프로빙 패킷만 전송되는 결과를 낳는다.

활성 경로에서 PATH_CHALLENGE를 수신한 엔드포인트는 응답으로 비프로빙 패킷을 보내야 SHOULD 한다. 비프로빙 패킷이 공격자가 만든 복사본보다 먼저 도착하면, 연결은 원래 경로로 다시 마이그레이션된다. 이후 다른 경로로의 모든 마이그레이션은 이 전체 과정을 다시 시작한다.

이 방어는 완벽하지 않지만, 심각한 문제로 간주되지는 않는다. 여러 번 원래 경로를 사용하려고 시도했음에도 공격을 통한 경로가 원래 경로보다 안정적으로 더 빠르다면, 공격과 라우팅 개선을 구분하는 것은 불가능하다.

엔드포인트는 이러한 유형의 공격 탐지를 개선하기 위해 휴리스틱을 사용할 수도 있다. 예를 들어, 이전 경로에서 최근에 패킷이 수신되었다면 NAT 리바인딩은 가능성이 낮다. 마찬가지로 IPv6 경로에서는 리바인딩이 드물다. 엔드포인트는 중복된 패킷을 찾을 수도 있다. 반대로, 연결 ID의 변경은 공격보다는 의도적인 마이그레이션을 나타낼 가능성이 더 높다.

9.4. 손실 감지 및 혼잡 제어

새 경로에서 사용 가능한 용량은 이전 경로와 같지 않을 수 있다. 이전 경로에서 전송된 패킷은 새 경로의 혼잡 제어나 RTT 추정에 기여해서는 MUST NOT 안 된다.

피어가 새 주소를 소유함을 확인하면, 엔드포인트는 피어 주소의 유일한 변경이 포트 번호인 경우를 제외하고, 새 경로에 대한 혼잡 제어기와 왕복 시간 추정기를 즉시 초기값으로 재설정해야 MUST 한다([QUIC-RECOVERY]의 Appendices A.3B.3 참조). 포트만 변경되는 경우는 흔히 NAT 리바인딩이나 다른 미들박스 활동의 결과이므로, 엔드포인트는 이러한 경우 초기값으로 되돌리는 대신 혼잡 제어 상태와 왕복 시간 추정치를 유지할 수 MAY 있다. 이전 경로에서 유지된 혼잡 제어 상태가 상당히 다른 특성을 가진 새 경로에서 사용되는 경우, 송신자는 혼잡 제어기와 RTT 추정기가 적응할 때까지 너무 공격적으로 전송할 수 있다. 일반적으로 구현은 새 경로에서 이전 값을 사용할 때 주의하는 것이 권고된다.

마이그레이션 기간 동안 엔드포인트가 여러 주소에서/여러 주소로 데이터와 프로브를 보낼 때, 결과적으로 두 경로의 왕복 시간이 다를 수 있으므로 수신자에게 겉보기 재정렬이 있을 수 있다. 여러 경로에서 패킷을 수신하는 수신자는 여전히 수신한 모든 패킷을 포함하는 ACK 프레임을 보낸다.

연결 마이그레이션 중 여러 경로가 사용될 수 있지만, 단일 혼잡 제어 컨텍스트와 단일 손실 복구 컨텍스트([QUIC-RECOVERY]에 설명된 것처럼)로 충분할 수 있다. 예를 들어, 엔드포인트는 이전 경로가 더 이상 필요하지 않다는 것이 확인될 때까지(예: Section 9.3.3에 설명된 경우) 새 혼잡 제어 컨텍스트로 전환하는 것을 지연할 수 있다.

송신자는 프로브 패킷에 대해 예외를 두어, 해당 패킷의 손실 감지가 독립적이고 혼잡 제어기가 전송 속도를 부당하게 줄이지 않도록 할 수 있다. 엔드포인트는 PATH_CHALLENGE가 전송될 때 별도 타이머를 설정할 수 있으며, 해당 PATH_RESPONSE가 수신되면 이 타이머는 취소된다. PATH_RESPONSE가 수신되기 전에 타이머가 만료되면, 엔드포인트는 새 PATH_CHALLENGE를 보내고 더 긴 기간으로 타이머를 다시 시작할 수 있다. 이 타이머는 Section 6.2.1 of [QUIC-RECOVERY]에 설명된 대로 설정되어야 SHOULD 하며, 더 공격적이어서는 MUST NOT 안 된다.

9.5. 연결 마이그레이션의 프라이버시 영향

여러 네트워크 경로에서 안정적인 연결 ID를 사용하면 수동 관찰자가 해당 경로들 사이의 활동을 상관시킬 수 있다. 네트워크 사이를 이동하는 엔드포인트는 피어 이외의 어떤 엔티티도 자신의 활동을 상관시키는 것을 원하지 않을 수 있으므로, Section 5.1에서 논의된 것처럼 서로 다른 로컬 주소에서 보낼 때 서로 다른 연결 ID를 사용한다. 이것이 효과적이려면, 엔드포인트는 자신이 제공하는 연결 ID가 다른 어떤 엔티티에 의해서도 연결될 수 없도록 보장해야 한다.

언제든 엔드포인트는 전송에 사용하는 Destination Connection ID를 다른 경로에서 사용되지 않은 값으로 변경할 수 MAY 있다.

엔드포인트는 둘 이상의 로컬 주소에서 보낼 때 연결 ID를 재사용해서는 MUST NOT 안 된다. 예를 들어 Section 9.2에 설명된 대로 연결 마이그레이션을 시작할 때 또는 Section 9.1에 설명된 대로 새 네트워크 경로를 탐색할 때가 그렇다.

마찬가지로, 엔드포인트는 둘 이상의 목적지 주소로 보낼 때 연결 ID를 재사용해서는 MUST NOT 안 된다. 피어가 제어할 수 없는 네트워크 변경으로 인해 엔드포인트는 같은 Destination Connection ID 필드 값을 가진 패킷을 새 소스 주소에서 수신할 수 있으며, 이 경우 엔드포인트는 같은 로컬 주소에서 보내는 동안 새 원격 주소와 함께 현재 연결 ID를 계속 사용할 수 MAY 있다.

연결 ID 재사용에 관한 이러한 요구사항은 패킷 전송에만 적용된다. 연결 ID 변경 없이도 의도치 않은 경로 변경이 가능하기 때문이다. 예를 들어, 네트워크 비활성 기간 후 클라이언트가 전송을 재개할 때 NAT 리바인딩으로 인해 새 경로에서 패킷이 전송될 수 있다. 엔드포인트는 이러한 이벤트에 Section 9.3에 설명된 대로 응답한다.

각 새 네트워크 경로에서 양방향으로 전송되는 패킷에 서로 다른 연결 ID를 사용하면, 서로 다른 네트워크 경로에 걸쳐 같은 연결의 패킷을 연결하는 데 연결 ID가 사용되는 것을 제거한다. 헤더 보호는 패킷 번호가 활동을 상관시키는 데 사용될 수 없도록 보장한다. 이것이 타이밍이나 크기와 같은 패킷의 다른 속성이 활동을 상관시키는 데 사용되는 것을 막지는 않는다.

엔드포인트는 길이가 0인 연결 ID를 요청한 피어와 마이그레이션을 시작해서는 SHOULD NOT 안 된다. 새 경로의 트래픽이 이전 경로의 트래픽과 쉽게 연결될 수 있기 때문이다. 서버가 길이가 0인 연결 ID를 가진 패킷을 올바른 연결과 연결할 수 있다면, 이는 서버가 패킷을 역다중화하기 위해 다른 정보를 사용하고 있음을 의미한다. 예를 들어, 서버는 모든 클라이언트에게 고유한 주소를 제공할 수 있다. 예컨대 HTTP 대체 서비스 [ALTSVC]를 사용하는 방식이다. 여러 네트워크 경로에 걸쳐 패킷을 올바르게 라우팅할 수 있게 하는 정보는 피어 이외의 엔티티가 해당 경로의 활동을 연결할 수 있게도 한다.

클라이언트는 비활성 기간 후 트래픽을 보낼 때 새 연결 ID, 소스 UDP 포트 또는 IP 주소([RFC8981] 참조)로 전환하여 연결 가능성을 줄이고 싶을 수 있다. 패킷을 보내는 주소를 동시에 변경하면 서버가 연결 마이그레이션을 감지할 수 있다. 이는 NAT 리바인딩이나 실제 마이그레이션을 경험하지 않는 클라이언트의 경우에도 마이그레이션을 지원하는 메커니즘이 실행되도록 보장한다. 주소 변경은 피어가 혼잡 제어 상태를 재설정하게 할 수 있으므로 (Section 9.4 참조), 주소는 드물게만 변경되어야 SHOULD 한다.

사용 가능한 연결 ID를 모두 소진한 엔드포인트는 새 경로를 탐색하거나 마이그레이션을 시작할 수 없으며, 피어의 프로브나 마이그레이션 시도에 응답할 수도 없다. 마이그레이션이 가능하고 서로 다른 경로에서 전송된 패킷이 상관되지 않도록 보장하기 위해, 엔드포인트는 피어가 마이그레이션하기 전에 새 연결 ID를 제공해야 SHOULD 한다. Section 5.1.1을 참조한다. 피어가 사용 가능한 연결 ID를 소진했을 수 있는 경우, 마이그레이션하는 엔드포인트는 새 네트워크 경로에서 전송되는 모든 패킷에 NEW_CONNECTION_ID 프레임을 포함할 수 있다.

9.6. 서버의 선호 주소

QUIC는 서버가 하나의 IP 주소에서 연결을 수락한 뒤 핸드셰이크 직후 이러한 연결을 더 선호되는 주소로 이전하려 시도할 수 있게 한다. 이는 클라이언트가 처음에는 여러 서버가 공유하는 주소에 연결하지만, 연결 안정성을 보장하기 위해 유니캐스트 주소 사용을 선호하는 경우 특히 유용하다. 이 섹션은 연결을 선호되는 서버 주소로 마이그레이션하기 위한 프로토콜을 설명한다.

연결 중간에 새 서버 주소로 연결을 마이그레이션하는 것은 이 문서에 명시된 QUIC 버전에서 지원되지 않는다. 클라이언트가 그 주소로 마이그레이션을 시작하지 않았는데 새 서버 주소에서 패킷을 수신하면, 클라이언트는 이러한 패킷을 폐기해야 SHOULD 한다.

9.6.1. 선호 주소 전달

서버는 TLS 핸드셰이크에 preferred_address 전송 매개변수를 포함하여 선호 주소를 전달한다.

서버는 클라이언트가 자신의 네트워크 접속에 가장 적합한 주소를 선택할 수 있도록 각 주소 패밀리(IPv4 및 IPv6)의 선호 주소를 전달할 수 MAY 있다.

핸드셰이크가 확인되면, 클라이언트는 서버가 제공한 두 주소 중 하나를 선택하고 경로 검증을 시작해야 SHOULD 한다(Section 8.2 참조). 클라이언트는 preferred_address 전송 매개변수 또는 NEW_CONNECTION_ID 프레임에서 가져온 이전에 사용되지 않은 활성 연결 ID를 사용하여 패킷을 구성한다.

경로 검증이 성공하자마자, 클라이언트는 새 연결 ID를 사용하여 앞으로의 모든 패킷을 새 서버 주소로 보내기 시작하고 이전 서버 주소 사용을 중단해야 SHOULD 한다. 경로 검증이 실패하면, 클라이언트는 앞으로의 모든 패킷을 서버의 원래 IP 주소로 계속 보내야 MUST 한다.

9.6.2. 선호 주소로 마이그레이션

선호 주소로 마이그레이션하는 클라이언트는 마이그레이션하기 전에 자신이 선택한 주소를 검증해야 MUST 한다. Section 21.5.3을 참조한다.

서버는 연결을 수락한 후 언제든 자신의 선호 IP 주소로 향하는 패킷을 수신할 수 있다. 이 패킷이 PATH_CHALLENGE 프레임을 포함하는 경우, 서버는 Section 8.2에 따라 PATH_RESPONSE 프레임을 포함하는 패킷을 보낸다. 서버는 자신의 선호 주소에서 클라이언트로부터 비프로빙 패킷을 수신하고 새 경로를 검증할 때까지, 원래 주소에서 비프로빙 패킷을 보내야 MUST 한다.

서버는 자신의 선호 주소에서 클라이언트 쪽 경로를 탐색해야 MUST 한다. 이는 공격자가 시작한 허위 마이그레이션을 방지하는 데 도움이 된다.

서버가 경로 검증을 완료하고 자신의 선호 주소에서 새로운 최대 패킷 번호를 가진 비프로빙 패킷을 수신하면, 서버는 선호 IP 주소에서만 클라이언트에게 비프로빙 패킷을 보내기 시작한다. 서버는 이전 IP 주소에서 수신되는 이 연결의 더 새로운 패킷을 삭제해야 SHOULD 한다. 서버는 이전 IP 주소에서 수신되는 지연된 패킷을 계속 처리할 수 MAY 있다.

서버가 preferred_address 전송 매개변수에서 제공하는 주소는 제공된 연결에서만 유효하다. 클라이언트는 현재 연결에서 재개된 연결을 포함하여 다른 연결에 이러한 주소를 사용해서는 MUST NOT 안 된다.

9.6.3. 클라이언트 마이그레이션과 선호 주소의 상호작용

클라이언트는 서버의 선호 주소로 마이그레이션하기 전에 연결 마이그레이션을 수행해야 할 수 있다. 이 경우 클라이언트는 클라이언트의 새 주소에서 원래 서버 주소와 선호 서버 주소 모두에 대해 경로 검증을 동시에 수행해야 SHOULD 한다.

서버의 선호 주소에 대한 경로 검증이 성공하면, 클라이언트는 원래 주소의 검증을 포기하고 서버의 선호 주소를 사용하도록 마이그레이션해야 MUST 한다. 서버의 선호 주소에 대한 경로 검증은 실패하지만 서버의 원래 주소 검증이 성공하면, 클라이언트는 자신의 새 주소로 마이그레이션하고 서버의 원래 주소로 계속 보낼 수 MAY 있다.

서버의 선호 주소에서 수신된 패킷의 소스 주소가 핸드셰이크 중 클라이언트에서 관찰된 주소와 다르면, 서버는 Sections 9.3.19.3.2에 설명된 잠재적 공격으로부터 보호해야 MUST 한다. 의도적인 동시 마이그레이션 외에도, 이는 클라이언트의 접근 네트워크가 서버의 선호 주소에 대해 다른 NAT 바인딩을 사용했기 때문에 발생할 수 있다.

서버는 다른 주소에서 프로브 패킷을 수신하면 클라이언트의 새 주소로 경로 검증을 시작해야 SHOULD 한다. Section 8을 참조한다.

새 주소로 마이그레이션하는 클라이언트는 서버에 대해 같은 주소 패밀리의 선호 주소를 사용해야 SHOULD 한다.

preferred_address 전송 매개변수에서 제공되는 연결 ID는 제공되는 주소에 특정되지 않는다. 이 연결 ID는 클라이언트가 마이그레이션에 사용할 연결 ID를 갖도록 보장하기 위해 제공되지만, 클라이언트는 이 연결 ID를 어떤 경로에서도 사용할 수 MAY 있다.

9.7. IPv6 흐름 레이블 사용과 마이그레이션

IPv6를 사용하여 데이터를 보내는 엔드포인트는 로컬 API가 IPv6 흐름 레이블 설정을 허용하지 않는 경우를 제외하고, [RFC6437]을 준수하여 IPv6 흐름 레이블을 적용해야 SHOULD 한다.

흐름 레이블 생성은 이전에 사용된 흐름 레이블과의 연결 가능성을 최소화하도록 설계되어야 MUST 한다. 안정적인 흐름 레이블은 여러 경로의 활동을 상관시킬 수 있기 때문이다. Section 9.5를 참조한다.

[RFC6437]은 흐름 레이블을 생성하기 위해 의사난수 함수를 사용해 값을 파생할 것을 제안한다. 흐름 레이블 생성 시 소스 및 목적지 주소에 더해 Destination Connection ID 필드를 포함하면, 다른 관찰 가능한 식별자의 변경과 변경이 동기화되도록 보장된다. 이러한 입력을 로컬 비밀과 결합하는 암호화 해시 함수는 이를 구현할 수 있는 한 가지 방법이다.

10. 연결 종료

설정된 QUIC 연결은 다음 세 가지 방법 중 하나로 종료될 수 있다:

엔드포인트는 패킷을 보낼 수 있는 검증된 경로가 없으면 연결 상태를 폐기할 수 MAY 있다. Section 8.2를 참조한다.

10.1. 유휴 타임아웃

어느 한 엔드포인트가 자신의 전송 매개변수(Section 18.2)에서 max_idle_timeout을 지정한 경우, 연결이 양쪽 엔드포인트가 광고한 max_idle_timeout 값의 최소값보다 더 오래 유휴 상태로 남아 있으면, 연결은 조용히 닫히고 그 상태는 폐기된다.

각 엔드포인트는 max_idle_timeout을 광고하지만, 엔드포인트에서의 유효 값은 두 광고 값의 최소값(또는 한 엔드포인트만 0이 아닌 값을 광고하는 경우 그 유일한 광고 값)으로 계산된다. max_idle_timeout을 알림으로써, 엔드포인트는 유효 값 이전에 연결을 포기하는 경우 즉시 닫기(Section 10.2)를 시작하겠다고 약속한다.

엔드포인트는 피어로부터 패킷을 수신하고 성공적으로 처리하면 자신의 유휴 타이머를 다시 시작한다. 또한 엔드포인트는 마지막으로 패킷을 수신하고 처리한 이후 다른 ack-eliciting 패킷을 보내지 않았다면, ack-eliciting 패킷을 보낼 때도 유휴 타이머를 다시 시작한다. 패킷을 보낼 때 이 타이머를 다시 시작하면 새 활동이 시작된 후 연결이 닫히지 않도록 보장한다.

지나치게 작은 유휴 타임아웃 기간을 피하기 위해, 엔드포인트는 유휴 타임아웃 기간을 현재 Probe Timeout(PTO)의 최소 세 배로 늘려야 MUST 한다. 이는 여러 PTO가 만료되어 여러 프로브가 전송되고 손실될 수 있도록 한 뒤 유휴 타임아웃이 발생하게 한다.

10.1.1. 활성 여부 테스트

유효 타임아웃에 가까운 시점에 패킷을 보내는 엔드포인트는 이러한 패킷이 피어에서 폐기될 위험이 있다. 해당 패킷이 도착하기 전에 피어에서 유휴 타임아웃 기간이 만료되었을 수 있기 때문이다.

엔드포인트는 피어가 곧 타임아웃될 수 있는 경우, 예를 들어 PTO 이내인 경우, 연결의 활성 여부를 테스트하기 위해 PING 또는 다른 ack-eliciting 프레임을 보낼 수 있다. Section 6.2 of [QUIC-RECOVERY]를 참조한다. 이는 사용 가능한 애플리케이션 데이터를 안전하게 재시도할 수 없는 경우 특히 유용하다. 어떤 데이터가 재시도에 안전한지는 애플리케이션이 결정한다는 점에 유의한다.

10.1.2. 유휴 타임아웃 연기

응답 데이터를 기대하지만 애플리케이션 데이터가 없거나 보낼 수 없는 경우, 엔드포인트는 유휴 타임아웃을 피하기 위해 ack-eliciting 패킷을 보내야 할 수 있다.

QUIC 구현은 애플리케이션에 유휴 타임아웃을 연기하는 옵션을 제공할 수 있다. 이 기능은 애플리케이션이 열린 연결과 관련된 상태를 잃지 않기를 원하지만 한동안 애플리케이션 데이터를 교환할 것으로 기대하지 않는 경우 사용할 수 있다. 이 옵션을 사용하면, 엔드포인트는 PING 프레임(Section 19.2)을 주기적으로 보낼 수 있으며, 이는 피어가 자신의 유휴 타임아웃 기간을 다시 시작하게 한다. PING 프레임을 포함하는 패킷을 보내는 것도, 패킷을 수신한 이후 처음 보내는 ack-eliciting 패킷이라면 이 엔드포인트의 유휴 타임아웃을 다시 시작한다. PING 프레임을 보내면 피어가 확인 응답으로 응답하게 하며, 이는 엔드포인트의 유휴 타임아웃도 다시 시작한다.

QUIC를 사용하는 애플리케이션 프로토콜은 유휴 타임아웃을 연기하는 것이 언제 적절한지에 대한 지침을 제공해야 SHOULD 한다. 불필요한 PING 프레임 전송은 성능에 해로운 영향을 줄 수 있다.

max_idle_timeout 전송 매개변수를 사용해 협상된 시간보다 더 긴 기간 동안 패킷이 전송되거나 수신되지 않으면 연결은 타임아웃된다. Section 10을 참조한다. 그러나 미들박스의 상태는 그보다 더 빨리 타임아웃될 수 있다. [RFC4787]의 REQ-5가 2분 타임아웃 간격을 권장하지만, 경험상 UDP 흐름에 대한 상태를 대다수의 미들박스가 잃지 않도록 하려면 30초마다 패킷을 보내는 것이 필요하다 [GATEWAY].

10.2. 즉시 닫기

엔드포인트는 연결을 즉시 종료하기 위해 CONNECTION_CLOSE 프레임 (Section 19.19)을 보낸다. CONNECTION_CLOSE 프레임은 모든 스트림이 즉시 닫힌 상태가 되게 한다. 열린 스트림은 암묵적으로 재설정된 것으로 간주할 수 있다.

CONNECTION_CLOSE 프레임을 보낸 후, 엔드포인트는 즉시 closing 상태에 들어간다. Section 10.2.1을 참조한다. CONNECTION_CLOSE 프레임을 수신한 후, 엔드포인트는 draining 상태에 들어간다. Section 10.2.2를 참조한다.

프로토콜 위반은 즉시 닫기로 이어진다.

즉시 닫기는 애플리케이션 프로토콜이 연결 닫기를 준비한 후 사용할 수 있다. 이는 애플리케이션 프로토콜이 정상 종료를 협상한 이후일 수 있다. 애플리케이션 프로토콜은 양쪽 애플리케이션 엔드포인트가 연결을 닫아도 된다는 것에 동의하는 데 필요한 메시지를 교환할 수 있으며, 그 후 애플리케이션은 QUIC에게 연결을 닫도록 요청한다. 결과적으로 QUIC가 연결을 닫을 때, 애플리케이션이 제공한 오류 코드가 있는 CONNECTION_CLOSE 프레임이 피어에게 닫힘을 신호하는 데 사용된다.

closing 및 draining 연결 상태는 연결이 깔끔하게 닫히고 지연되거나 재정렬된 패킷이 올바르게 폐기되도록 보장하기 위해 존재한다. 이러한 상태는 [QUIC-RECOVERY]에 정의된 현재 PTO 간격의 최소 세 배 동안 지속되어야 SHOULD 한다.

closing 또는 draining 상태를 벗어나기 전에 연결 상태를 폐기하면, 늦게 도착한 패킷을 수신할 때 엔드포인트가 불필요하게 Stateless Reset을 생성할 수 있다. 늦게 도착한 패킷이 응답을 유발하지 않도록 보장할 수 있는 다른 수단이 있는 엔드포인트, 예를 들어 UDP 소켓을 닫을 수 있는 엔드포인트는 더 빠른 리소스 회수를 위해 이러한 상태를 더 일찍 종료할 수 MAY 있다. 새 연결을 수락하기 위해 열린 소켓을 유지하는 서버는 closing 또는 draining 상태를 일찍 종료해서는 SHOULD NOT 안 된다.

closing 또는 draining 상태가 끝나면, 엔드포인트는 모든 연결 상태를 폐기해야 SHOULD 한다. 엔드포인트는 이 연결에 속하는 이후의 모든 들어오는 패킷에 대한 응답으로 Stateless Reset을 보낼 수 MAY 있다.

10.2.1. 닫는 연결 상태

엔드포인트는 즉시 닫기를 시작한 후 closing 상태에 들어간다.

closing 상태에서 엔드포인트는 CONNECTION_CLOSE 프레임을 포함하는 패킷을 생성하고 패킷이 해당 연결에 속하는지 식별하는 데 충분한 정보만 유지한다. closing 상태의 엔드포인트는 연결에 귀속하는 모든 들어오는 패킷에 대한 응답으로 CONNECTION_CLOSE 프레임을 포함하는 패킷을 보낸다.

엔드포인트는 closing 상태에서 패킷을 생성하는 속도를 제한해야 SHOULD 한다. 예를 들어, 엔드포인트는 수신된 패킷에 응답하기 전에 점진적으로 증가하는 수의 수신 패킷이나 시간을 기다릴 수 있다.

엔드포인트가 선택한 연결 ID와 QUIC 버전은 닫히는 연결의 패킷을 식별하기에 충분한 정보이다. 엔드포인트는 다른 모든 연결 상태를 폐기할 수 MAY 있다. 닫히는 중인 엔드포인트는 수신한 어떤 프레임도 처리할 필요가 없다. 엔드포인트는 CONNECTION_CLOSE 프레임을 읽고 처리할 수 있도록 들어오는 패킷의 패킷 보호 키를 유지할 수 MAY 있다.

엔드포인트는 closing 상태에 들어갈 때 패킷 보호 키를 버리고, 수신되는 모든 UDP 데이터그램에 대한 응답으로 CONNECTION_CLOSE 프레임을 포함하는 패킷을 보낼 수 MAY 있다. 그러나 패킷 보호 키를 폐기한 엔드포인트는 유효하지 않은 패킷을 식별하고 폐기할 수 없다. 증폭 공격에 사용되는 것을 피하기 위해, 이러한 엔드포인트는 자신이 보내는 패킷의 누적 크기를 연결에 귀속되어 수신된 패킷의 누적 크기의 세 배로 제한해야 MUST 한다. 엔드포인트가 닫히는 연결에 대해 유지하는 상태를 최소화하기 위해, 엔드포인트는 수신한 모든 패킷에 대한 응답으로 정확히 같은 패킷을 보낼 수 MAY 있다.

closing 상태에 있는 동안, 엔드포인트는 새 소스 주소에서 패킷을 수신할 수 있으며, 이는 연결 마이그레이션을 나타낼 수 있다. Section 9를 참조한다. closing 상태의 엔드포인트는 검증되지 않은 주소에서 수신된 패킷을 폐기하거나, 검증되지 않은 주소로 보내는 패킷의 누적 크기를 해당 주소에서 수신한 패킷 크기의 세 배로 제한해야 MUST 한다.

엔드포인트는 닫히는 중에는 키 업데이트를 처리할 것으로 기대되지 않는다 (Section 6 of [QUIC-TLS]). 키 업데이트는 엔드포인트가 이후 수신된 패킷을 처리할 수 없게 하므로 closing 상태에서 draining 상태로 이동하는 것을 막을 수 있지만, 그 밖에는 영향을 주지 않는다.

10.2.2. 드레이닝 연결 상태

엔드포인트가 CONNECTION_CLOSE 프레임을 수신하면 draining 상태에 들어간다. 이는 피어가 closing 또는 draining 중임을 나타낸다. 그 외에는 closing 상태와 동일하지만, draining 상태의 엔드포인트는 어떠한 패킷도 보내서는 MUST NOT 안 된다. 연결이 draining 상태에 들어가면 패킷 보호 키를 유지할 필요가 없다.

CONNECTION_CLOSE 프레임을 수신한 엔드포인트는 draining 상태에 들어가기 전에, 적절하다면 NO_ERROR 코드를 사용하여 CONNECTION_CLOSE 프레임을 포함하는 단일 패킷을 보낼 수 MAY 있다. 엔드포인트는 이후 패킷을 보내서는 MUST NOT 안 된다. 그렇게 하면 한 엔드포인트가 closing 상태를 벗어날 때까지 CONNECTION_CLOSE 프레임의 지속적인 교환이 발생할 수 있다.

엔드포인트는 피어도 closing 또는 draining 중임을 나타내는 CONNECTION_CLOSE 프레임을 수신하면, closing 상태에서 draining 상태로 들어갈 수 MAY 있다. 이 경우 draining 상태는 closing 상태가 끝났을 때 끝난다. 즉, 엔드포인트는 같은 종료 시간을 사용하지만 이 연결에서 모든 패킷 전송을 중단한다.

10.2.3. 핸드셰이크 중 즉시 닫기

CONNECTION_CLOSE 프레임을 보낼 때 목표는 피어가 그 프레임을 처리하도록 보장하는 것이다. 일반적으로 이는 패킷이 폐기되는 것을 피하기 위해 가장 높은 수준의 패킷 보호가 적용된 패킷에 프레임을 보내는 것을 의미한다. 핸드셰이크가 확인된 후(Section 4.1.2 of [QUIC-TLS] 참조), 엔드포인트는 모든 CONNECTION_CLOSE 프레임을 1-RTT 패킷으로 보내야 MUST 한다. 그러나 핸드셰이크가 확인되기 전에는 더 높은 단계의 패킷 보호 키가 피어에게 사용 가능하지 않을 수 있으므로, 더 낮은 패킷 보호 수준을 사용하는 패킷으로 또 다른 CONNECTION_CLOSE 프레임을 보낼 수 MAY 있다. 더 구체적으로는:

  • 클라이언트는 항상 서버가 Handshake 키를 가지고 있는지 알 수 있지만(Section 17.2.2.1 참조), 서버는 클라이언트가 Handshake 키를 가지고 있는지 모를 수 있다. 이러한 상황에서 서버는 클라이언트가 최소 하나를 처리할 수 있도록 Handshake 및 Initial 패킷 모두에 CONNECTION_CLOSE 프레임을 보내야 SHOULD 한다.
  • 0-RTT 패킷으로 CONNECTION_CLOSE 프레임을 보내는 클라이언트는 서버가 0-RTT를 수락했음을 보장받을 수 없다. Initial 패킷으로 CONNECTION_CLOSE 프레임을 보내면, 애플리케이션 오류 코드가 수신되지 않을 수 있더라도 서버가 닫기 신호를 수신할 가능성이 커진다.
  • 핸드셰이크가 확인되기 전에, 피어는 1-RTT 패킷을 처리할 수 없을 수 있으므로, 엔드포인트는 Handshake 및 1-RTT 패킷 모두에 CONNECTION_CLOSE 프레임을 보내야 SHOULD 한다. 서버는 또한 Initial 패킷에 CONNECTION_CLOSE 프레임을 보내야 SHOULD 한다.

Initial 또는 Handshake 패킷으로 type 0x1d의 CONNECTION_CLOSE를 보내면 애플리케이션 상태가 노출되거나 애플리케이션 상태를 변경하는 데 사용될 수 있다. Initial 또는 Handshake 패킷으로 프레임을 보낼 때 type 0x1d의 CONNECTION_CLOSE는 type 0x1c의 CONNECTION_CLOSE로 대체되어야 MUST 한다. 그렇지 않으면 애플리케이션 상태에 관한 정보가 드러날 수 있다. 엔드포인트는 Reason Phrase 필드 값을 지워야 MUST 하며, type 0x1c의 CONNECTION_CLOSE로 변환할 때 APPLICATION_ERROR 코드를 사용해야 SHOULD 한다.

여러 패킷 유형으로 전송되는 CONNECTION_CLOSE 프레임은 단일 UDP 데이터그램으로 병합될 수 있다. Section 12.2를 참조한다.

엔드포인트는 Initial 패킷으로 CONNECTION_CLOSE 프레임을 보낼 수 있다. 이는 Initial 또는 Handshake 패킷에서 수신한 인증되지 않은 정보에 대한 응답일 수 있다. 이러한 즉시 닫기는 정상적인 연결을 서비스 거부에 노출시킬 수 있다. QUIC는 핸드셰이크 중 경로상 공격에 대한 방어 조치를 포함하지 않는다. Section 21.2를 참조한다. 그러나 정상적인 피어에 대한 오류 피드백을 줄이는 대가로, 엔드포인트가 CONNECTION_CLOSE로 연결을 종료하는 대신 불법 패킷을 폐기하면 일부 형태의 서비스 거부를 공격자에게 더 어렵게 만들 수 있다. 이러한 이유로, 엔드포인트는 인증이 없는 패킷에서 오류가 감지되면 즉시 닫는 대신 패킷을 폐기할 수 MAY 있다.

Initial 패킷에서 오류를 감지한 서버와 같이 상태를 설정하지 않은 엔드포인트는 closing 상태에 들어가지 않는다. 연결에 대한 상태가 없는 엔드포인트는 CONNECTION_CLOSE 프레임을 보낼 때 closing 또는 draining 기간에 들어가지 않는다.

10.3. 상태 없는 재설정

상태 없는 재설정은 연결 상태에 접근할 수 없는 엔드포인트를 위한 최후의 수단 옵션으로 제공된다. 충돌이나 중단으로 인해 피어가 연결을 제대로 계속할 수 없는 엔드포인트로 데이터를 계속 보낼 수 있다. 엔드포인트는 활성 연결과 연관시킬 수 없는 패킷을 수신한 것에 대한 응답으로 Stateless Reset을 보낼 수 MAY 있다.

상태 없는 재설정은 활성 연결의 오류를 나타내는 데 적절하지 않다. 치명적인 연결 오류를 전달하려는 엔드포인트는 가능하다면 CONNECTION_CLOSE 프레임을 사용해야 MUST 한다.

이 과정을 지원하기 위해, 엔드포인트는 추측하기 어려운 16바이트 값인 stateless reset token을 발급한다. 피어가 이후 해당 stateless reset token으로 끝나는 UDP 데이터그램인 Stateless Reset을 수신하면, 피어는 즉시 연결을 종료한다.

stateless reset token은 연결 ID에 특정된다. 엔드포인트는 NEW_CONNECTION_ID 프레임의 Stateless Reset Token 필드에 값을 포함하여 stateless reset token을 발급한다. 서버는 핸드셰이크 중 자신이 선택한 연결 ID에 적용되는 stateless_reset_token 전송 매개변수도 발급할 수 있다. 이러한 교환은 암호화로 보호되므로 클라이언트와 서버만 그 값을 안다. 클라이언트의 전송 매개변수에는 기밀성 보호가 없기 때문에 클라이언트는 stateless_reset_token 전송 매개변수를 사용할 수 없다는 점에 유의한다.

토큰은 관련된 연결 ID가 RETIRE_CONNECTION_ID 프레임(Section 19.16)을 통해 폐기될 때 무효화된다.

처리할 수 없는 패킷을 수신한 엔드포인트는 다음 레이아웃의 패킷을 보낸다 (Section 1.3 참조):

Stateless Reset {
  Fixed Bits (2) = 1,
  Unpredictable Bits (38..),
  Stateless Reset Token (128),
}
Figure 10: Stateless Reset

이 설계는 Stateless Reset이 가능한 한 짧은 헤더가 있는 일반 패킷과 구별되지 않도록 보장한다.

Stateless Reset은 패킷 헤더의 처음 두 비트부터 시작하여 전체 UDP 데이터그램을 사용한다. 첫 바이트의 나머지 부분과 그 뒤의 임의 개수의 바이트는 무작위와 구별되지 않아야 SHOULD 하는 값으로 설정된다. 데이터그램의 마지막 16바이트는 stateless reset token을 포함한다.

의도된 수신자 이외의 엔티티에게 Stateless Reset은 짧은 헤더가 있는 패킷처럼 보일 것이다. Stateless Reset이 유효한 QUIC 패킷처럼 보이려면, Unpredictable Bits 필드가 최소 38비트의 데이터(또는 5바이트에서 두 고정 비트를 뺀 값)를 포함해야 한다.

그 결과 최소 크기인 21바이트는 수신자가 연결 ID 사용을 요구하는 경우 Stateless Reset을 다른 패킷과 구별하기 어렵다는 것을 보장하지 않는다. 이를 달성하기 위해, 엔드포인트는 자신이 보내는 모든 패킷이 피어에게 패킷에 포함하도록 요청한 최소 연결 ID 길이보다 최소 22바이트 더 길도록 해야 SHOULD 하며, 필요하다면 PADDING 프레임을 추가한다. 이는 피어가 보내는 모든 Stateless Reset이 엔드포인트로 보내진 유효한 패킷과 구별되지 않도록 보장한다. 43바이트 이하의 패킷에 대한 응답으로 Stateless Reset을 보내는 엔드포인트는 응답 대상 패킷보다 1바이트 더 짧은 Stateless Reset을 보내야 SHOULD 한다.

이 값들은 stateless reset token이 패킷 보호 AEAD의 최소 확장과 같은 길이라고 가정한다. 엔드포인트가 더 큰 최소 확장을 가진 패킷 보호 방식을 협상할 수 있었다면 추가적인 예측 불가능한 바이트가 필요하다.

엔드포인트는 증폭에 사용되는 것을 피하기 위해 자신이 수신한 패킷보다 세 배 이상 큰 Stateless Reset을 보내서는 MUST NOT 안 된다. Section 10.3.3은 Stateless Reset 크기에 대한 추가 한도를 설명한다.

엔드포인트는 유효한 QUIC 패킷이 되기에 너무 작은 패킷을 폐기해야 MUST 한다. 예를 들어, [QUIC-TLS]에 정의된 AEAD 함수 집합에서는 21바이트보다 작은 짧은 헤더 패킷은 결코 유효하지 않다.

엔드포인트는 짧은 헤더가 있는 패킷으로 형식화된 Stateless Reset을 보내야 MUST 한다. 그러나 다른 QUIC 버전에서는 긴 헤더 사용을 허용할 수 있으므로, 엔드포인트는 유효한 stateless reset token으로 끝나는 모든 패킷을 Stateless Reset으로 처리해야 MUST 한다.

엔드포인트는 긴 헤더가 있는 패킷에 대한 응답으로 Stateless Reset을 보낼 수 MAY 있다. Stateless Reset 전송은 stateless reset token이 피어에게 사용 가능해지기 전에는 효과적이지 않다. 이 QUIC 버전에서 긴 헤더가 있는 패킷은 연결 설정 중에만 사용된다. stateless reset token은 연결 설정이 완료되거나 완료에 가까워질 때까지 사용할 수 없으므로, 알 수 없는 긴 헤더 패킷을 무시하는 것이 Stateless Reset을 보내는 것만큼 효과적일 수 있다.

엔드포인트는 짧은 헤더가 있는 패킷에서 Source Connection ID를 결정할 수 없다. 따라서 Stateless Reset에서 Destination Connection ID를 설정할 수 없다. 그러므로 Destination Connection ID는 이전 패킷에서 사용된 값과 달라진다. 임의의 Destination Connection ID는 연결 ID가 NEW_CONNECTION_ID 프레임을 사용해 제공된 새 연결 ID로 이동한 결과처럼 보이게 한다. Section 19.15를 참조한다.

무작위화된 연결 ID 사용은 두 가지 문제를 초래한다:

  • 패킷이 피어에 도달하지 않을 수 있다. Destination Connection ID가 피어 쪽 라우팅에 중요하다면, 이 패킷은 잘못 라우팅될 수 있다. 이는 응답으로 또 다른 Stateless Reset을 트리거할 수도 있다. Section 10.3.3을 참조한다. 올바르게 라우팅되지 않은 Stateless Reset은 효과적인 오류 감지 및 복구 메커니즘이 아니다. 이 경우 엔드포인트는 연결 실패를 감지하기 위해 타이머와 같은 다른 방법에 의존해야 한다.
  • 무작위로 생성된 연결 ID는 피어 이외의 엔티티가 이를 잠재적 Stateless Reset으로 식별하는 데 사용할 수 있다. 때때로 다른 연결 ID를 사용하는 엔드포인트는 이에 대해 어느 정도 불확실성을 도입할 수 있다.

이 상태 없는 재설정 설계는 QUIC 버전 1에 특정된다. 여러 QUIC 버전을 지원하는 엔드포인트는 자신이 지원할 수 있는(또는 상태를 잃기 전에 지원했을 수 있는) 모든 버전을 지원하는 피어가 수락할 Stateless Reset을 생성해야 한다. 새로운 QUIC 버전 설계자는 이를 인식하고 (1) 이 설계를 재사용하거나 (2) 마지막 16바이트가 아닌 패킷의 다른 부분을 데이터 운반에 사용해야 한다.

10.3.1. 상태 없는 재설정 감지

엔드포인트는 UDP 데이터그램의 마지막 16바이트를 사용하여 잠재적인 Stateless Reset을 감지한다. 엔드포인트는 자신이 최근 보낸 데이터그램의 연결 ID 및 원격 주소와 관련된 모든 stateless reset token을 기억한다. 여기에는 NEW_CONNECTION_ID 프레임의 Stateless Reset Token 필드 값과 서버의 전송 매개변수가 포함되지만, 사용되지 않았거나 폐기된 연결 ID와 관련된 stateless reset token은 제외된다. 엔드포인트는 데이터그램의 마지막 16바이트를 해당 데이터그램이 수신된 원격 주소와 관련된 모든 stateless reset token과 비교하여 수신한 데이터그램을 Stateless Reset으로 식별한다.

이 비교는 모든 인바운드 데이터그램에 대해 수행될 수 있다. 엔드포인트는 데이터그램의 어떤 패킷이라도 성공적으로 처리되면 이 검사를 생략할 수 MAY 있다. 그러나 들어오는 데이터그램의 첫 번째 패킷이 연결과 연관될 수 없거나 복호화될 수 없는 경우, 비교는 수행되어야 MUST 한다.

엔드포인트는 자신이 사용하지 않은 연결 ID나 폐기된 연결 ID와 관련된 stateless reset token을 검사해서는 MUST NOT 안 된다.

데이터그램을 stateless reset token 값과 비교할 때, 엔드포인트는 토큰 값에 대한 정보를 누출하지 않고 비교를 수행해야 MUST 한다. 예를 들어, 이 비교를 상수 시간으로 수행하면 타이밍 부채널을 통한 개별 stateless reset token 값의 정보 누출을 방지한다. 또 다른 접근 방식은 원시 토큰 값 대신 stateless reset token의 변환된 값을 저장하고 비교하는 것이다. 여기서 변환은 비밀 키를 사용하는 암호학적으로 안전한 의사난수 함수 (예: 블록 암호, Hashed Message Authentication Code(HMAC) [RFC2104])로 정의된다. 엔드포인트는 패킷이 성공적으로 복호화되었는지 또는 유효한 stateless reset token의 수에 대한 정보를 보호할 것으로 기대되지 않는다.

데이터그램의 마지막 16바이트가 stateless reset token과 같은 값을 가지면, 엔드포인트는 draining 기간에 들어가야 MUST 하며 이 연결에서 더 이상 어떤 패킷도 보내지 않아야 한다.

10.3.2. 상태 없는 재설정 토큰 계산

stateless reset token은 추측하기 어려워야 MUST 한다. stateless reset token을 만들기 위해 엔드포인트는 자신이 생성하는 모든 연결에 대해 비밀을 무작위로 생성할 수 있다 [RANDOM]. 그러나 이는 클러스터에 여러 인스턴스가 있는 경우 조정 문제를 만들거나, 상태를 잃을 수 있는 엔드포인트에는 저장 문제를 만든다. Stateless Reset은 특별히 상태가 손실된 경우를 처리하기 위해 존재하므로, 이 접근 방식은 최적이 아니다.

정적 키와 엔드포인트가 선택한 연결 ID(Section 5.1 참조)를 입력으로 받는 의사난수 함수를 사용해 증명을 생성함으로써, 같은 엔드포인트에 대한 모든 연결에서 단일 정적 키를 사용할 수 있다. 엔드포인트는 HMAC [RFC2104] (예: HMAC(static_key, connection_id)) 또는 HMAC-based Key Derivation Function(HKDF) [RFC5869] (예: 정적 키를 입력 키 자료로 사용하고 연결 ID를 salt로 사용)를 사용할 수 있다. 이 함수의 출력은 16바이트로 잘려 해당 연결의 stateless reset token을 생성한다.

상태를 잃은 엔드포인트는 같은 방법을 사용해 유효한 stateless reset token을 생성할 수 있다. 연결 ID는 엔드포인트가 수신하는 패킷에서 온다.

이 설계는 엔드포인트가 패킷의 연결 ID를 사용해 연결을 재설정할 수 있도록 피어가 항상 자신의 패킷에 연결 ID를 보내는 것에 의존한다. 이 설계를 사용하는 엔드포인트는 모든 연결에 같은 연결 ID 길이를 사용하거나, 상태 없이 복구할 수 있도록 연결 ID 길이를 인코딩해야 MUST 한다. 또한 길이가 0인 연결 ID를 제공할 수 없다.

stateless reset token을 공개하면 모든 엔티티가 연결을 종료할 수 있으므로, 값은 한 번만 사용할 수 있다. stateless reset token을 선택하는 이 방법은 연결 ID와 정적 키의 조합이 다른 연결에 사용되어서는 MUST NOT 안 된다는 것을 의미한다. 같은 정적 키를 공유하는 인스턴스가 같은 연결 ID를 사용하거나, 공격자가 상태가 없지만 같은 정적 키를 가진 인스턴스로 패킷이 라우팅되도록 만들 수 있다면 서비스 거부 공격이 가능하다. Section 21.11을 참조한다. stateless reset token을 공개하여 재설정된 연결의 연결 ID는 정적 키를 공유하는 노드에서 새 연결에 재사용되어서는 MUST NOT 안 된다.

같은 stateless reset token이 여러 연결 ID에 사용되어서는 MUST NOT 안 된다. 엔드포인트는 새 값을 모든 이전 값과 비교할 필요는 없지만, 중복 값은 PROTOCOL_VIOLATION 유형의 연결 오류로 처리될 수 MAY 있다.

Stateless Reset에는 어떤 암호화 보호도 없다는 점에 유의한다.

10.3.3. 루핑

Stateless Reset의 설계는 stateless reset token을 모르면 유효한 패킷과 구별할 수 없도록 되어 있다. 예를 들어 서버가 다른 서버에게 Stateless Reset을 보내면, 응답으로 또 다른 Stateless Reset을 수신할 수 있으며, 이는 무한한 교환으로 이어질 수 있다.

엔드포인트는 루핑을 방지할 만큼 충분한 상태를 유지하지 않는 한, 자신이 보내는 모든 Stateless Reset이 이를 유발한 패킷보다 작도록 보장해야 MUST 한다. 루프가 발생하면, 이로 인해 패킷이 결국 응답을 유발하기에 너무 작아진다.

엔드포인트는 자신이 보낸 Stateless Reset 수를 기억하고 한도에 도달하면 새 Stateless Reset 생성을 중단할 수 있다. 원격 주소마다 별도 한도를 사용하면 다른 피어나 연결이 한도를 소진했을 때도 Stateless Reset이 연결을 닫는 데 사용될 수 있도록 보장한다.

41바이트보다 작은 Stateless Reset은 피어의 연결 ID 길이에 따라 관찰자가 Stateless Reset으로 식별할 수 있을 수 있다. 반대로, 작은 패킷에 대한 응답으로 Stateless Reset을 보내지 않으면 아주 작은 패킷만 전송되는 끊어진 연결의 경우를 감지하는 데 Stateless Reset이 유용하지 않을 수 있다. 이러한 실패는 타이머와 같은 다른 수단으로만 감지될 수 있다.

11. 오류 처리

오류를 감지한 엔드포인트는 해당 오류의 존재를 피어에게 신호해야 SHOULD 한다. 전송 수준 오류와 애플리케이션 수준 오류는 모두 전체 연결에 영향을 줄 수 있다. Section 11.1을 참조한다. 애플리케이션 수준 오류만 단일 스트림으로 격리될 수 있다. Section 11.2를 참조한다.

오류를 신호하는 프레임에는 가장 적절한 오류 코드 (Section 20)가 포함되어야 SHOULD 한다. 이 명세가 오류 조건을 식별하는 경우, 사용되는 오류 코드도 식별한다. 이것들이 요구사항처럼 표현되어 있더라도, 서로 다른 구현 전략은 서로 다른 오류가 보고되도록 할 수 있다. 특히, 엔드포인트는 오류 조건을 감지할 때 적용 가능한 어떤 오류 코드든 사용할 수 MAY 있다. 일반 오류 코드(예: PROTOCOL_VIOLATION 또는 INTERNAL_ERROR)는 특정 오류 코드 대신 항상 사용할 수 있다.

상태 없는 재설정(Section 10.3)은 CONNECTION_CLOSE 또는 RESET_STREAM 프레임으로 신호할 수 있는 어떤 오류에도 적합하지 않다. 연결에서 프레임을 보낼 수 있는 데 필요한 상태를 가진 엔드포인트는 상태 없는 재설정을 사용해서는 MUST NOT 안 된다.

11.1. 연결 오류

프로토콜 의미론의 명백한 위반이나 전체 연결에 영향을 주는 상태 손상처럼 연결을 사용할 수 없게 만드는 오류는 CONNECTION_CLOSE 프레임 (Section 19.19)을 사용하여 신호해야 MUST 한다.

애플리케이션별 프로토콜 오류는 프레임 유형이 0x1d인 CONNECTION_CLOSE 프레임을 사용하여 신호된다. 이 문서에 설명된 모든 오류를 포함하여 전송에 특정된 오류는 프레임 유형이 0x1c인 CONNECTION_CLOSE 프레임에 운반된다.

CONNECTION_CLOSE 프레임은 손실되는 패킷으로 전송될 수 있다. 엔드포인트는 종료된 연결에서 더 많은 패킷을 수신하면 CONNECTION_CLOSE 프레임을 포함하는 패킷을 재전송할 준비가 되어 있어야 SHOULD 한다. 재전송 횟수와 이 최종 패킷이 전송되는 시간을 제한하면 종료된 연결에 소비되는 노력이 제한된다.

CONNECTION_CLOSE 프레임을 포함하는 패킷을 재전송하지 않기로 선택한 엔드포인트는 피어가 첫 번째 그러한 패킷을 놓칠 위험이 있다. 종료된 연결에 대해 계속 데이터를 수신하는 엔드포인트가 사용할 수 있는 유일한 메커니즘은 상태 없는 재설정 절차(Section 10.3)를 시도하는 것이다.

Initial 패킷에 대한 AEAD는 강한 인증을 제공하지 않으므로, 엔드포인트는 유효하지 않은 Initial 패킷을 폐기할 수 MAY 있다. 이 명세가 달리 연결 오류를 요구하는 경우에도 Initial 패킷을 폐기하는 것은 허용된다. 엔드포인트는 패킷 안의 프레임을 처리하지 않거나, 처리의 효과를 되돌리는 경우에만 패킷을 폐기할 수 있다. 유효하지 않은 Initial 패킷을 폐기하는 것은 서비스 거부에 대한 노출을 줄이는 데 사용될 수 있다. Section 21.2를 참조한다.

11.2. 스트림 오류

애플리케이션 수준 오류가 단일 스트림에 영향을 주지만 그 외에는 연결을 복구 가능한 상태로 남긴다면, 엔드포인트는 적절한 오류 코드가 있는 RESET_STREAM 프레임(Section 19.4)을 보내 영향받은 스트림만 종료할 수 있다.

애플리케이션 프로토콜의 관여 없이 스트림을 재설정하면 애플리케이션 프로토콜이 복구할 수 없는 상태로 들어갈 수 있다. RESET_STREAM은 QUIC를 사용하는 애플리케이션 프로토콜에 의해서만 시작되어야 MUST 한다.

RESET_STREAM에 운반되는 애플리케이션 오류 코드의 의미론은 애플리케이션 프로토콜이 정의한다. 애플리케이션 프로토콜만 스트림이 종료되도록 만들 수 있다. 애플리케이션 프로토콜의 로컬 인스턴스는 직접 API 호출을 사용하고, 원격 인스턴스는 STOP_SENDING 프레임을 사용하며, 이는 자동 RESET_STREAM을 트리거한다.

애플리케이션 프로토콜은 어느 엔드포인트에 의해 조기에 취소된 스트림을 처리하는 규칙을 정의해야 SHOULD 한다.

12. 패킷과 프레임

QUIC 엔드포인트는 패킷을 교환하여 통신한다. 패킷에는 기밀성 및 무결성 보호가 있다. Section 12.1을 참조한다. 패킷은 UDP 데이터그램에 운반된다. Section 12.2를 참조한다.

이 QUIC 버전은 연결 설정 중 긴 패킷 헤더를 사용한다. Section 17.2를 참조한다. 긴 헤더가 있는 패킷은 Initial (Section 17.2.2), 0-RTT (Section 17.2.3), Handshake (Section 17.2.4), 및 Retry(Section 17.2.5)이다. 버전 협상은 긴 헤더가 있는 버전 독립적인 패킷을 사용한다. Section 17.2.1을 참조한다.

짧은 헤더가 있는 패킷은 최소 오버헤드를 위해 설계되었으며, 연결이 설정되고 1-RTT 키를 사용할 수 있게 된 후 사용된다. Section 17.3을 참조한다.

12.1. 보호된 패킷

QUIC 패킷은 패킷 유형에 따라 서로 다른 수준의 암호화 보호를 가진다. 패킷 보호의 세부사항은 [QUIC-TLS]에 있으며, 이 섹션은 제공되는 보호의 개요를 포함한다.

Version Negotiation 패킷에는 암호화 보호가 없다. [QUIC-INVARIANTS]를 참조한다.

Retry 패킷은 우발적 수정을 방지하기 위해 AEAD 함수 [AEAD]를 사용한다.

Initial 패킷은 AEAD 함수를 사용하며, 이 함수의 키는 네트워크상에서 보이는 값을 사용해 파생된다. 따라서 Initial 패킷에는 효과적인 기밀성 보호가 없다. Initial 보호는 패킷의 송신자가 네트워크 경로상에 있음을 보장하기 위해 존재한다. 클라이언트로부터 Initial 패킷을 수신하는 모든 엔티티는 패킷의 내용을 읽고 어느 엔드포인트에서든 성공적으로 인증될 Initial 패킷을 생성할 수 있게 하는 키를 복구할 수 있다. AEAD는 또한 Initial 패킷을 우발적 수정으로부터 보호한다.

다른 모든 패킷은 암호화 핸드셰이크에서 파생된 키로 보호된다. 암호화 핸드셰이크는 통신하는 엔드포인트만 Handshake, 0-RTT 및 1-RTT 패킷에 해당하는 키를 수신하도록 보장한다. 0-RTT 및 1-RTT 키로 보호된 패킷은 강한 기밀성 및 무결성 보호를 가진다.

일부 패킷 유형에 나타나는 Packet Number 필드에는 헤더 보호의 일부로 적용되는 대체 기밀성 보호가 있다. 자세한 내용은 Section 5.4 of [QUIC-TLS]를 참조한다. 기본 패킷 번호는 주어진 패킷 번호 공간에서 전송되는 각 패킷마다 증가한다. 자세한 내용은 Section 12.3을 참조한다.

12.2. 패킷 병합

Initial(Section 17.2.2), 0-RTT(Section 17.2.3), 및 Handshake (Section 17.2.4) 패킷은 패킷의 끝을 결정하는 Length 필드를 포함한다. 길이는 Packet Number 및 Payload 필드를 모두 포함하며, 이 둘은 모두 기밀성 보호가 적용되고 처음에는 길이를 알 수 없다. Payload 필드의 길이는 헤더 보호가 제거된 후 알게 된다.

Length 필드를 사용하면 송신자는 여러 QUIC 패킷을 하나의 UDP 데이터그램으로 병합할 수 있다. 이는 암호화 핸드셰이크를 완료하고 데이터 전송을 시작하는 데 필요한 UDP 데이터그램 수를 줄일 수 있다. 또한 Path Maximum Transmission Unit(PMTU) 프로브를 구성하는 데 사용할 수 있다. Section 14.4.1을 참조한다. 수신자는 병합된 패킷을 처리할 수 있어야 MUST 한다.

암호화 수준이 증가하는 순서(Initial, 0-RTT, Handshake, 1-RTT; Section 4.1.4 of [QUIC-TLS] 참조)로 패킷을 병합하면 수신자가 단일 패스로 모든 패킷을 처리할 가능성이 높아진다. 짧은 헤더가 있는 패킷은 길이를 포함하지 않으므로 UDP 데이터그램에 포함된 마지막 패킷일 수밖에 없다. 엔드포인트는 같은 암호화 수준에서 보내야 하는 프레임들이라면, 같은 암호화 수준의 여러 패킷을 병합하는 대신 단일 패킷에 여러 프레임을 포함해야 SHOULD 한다.

수신자는 UDP 데이터그램에 포함된 첫 번째 패킷의 정보를 기반으로 라우팅할 수 MAY 있다. 송신자는 서로 다른 연결 ID를 가진 QUIC 패킷을 단일 UDP 데이터그램으로 병합해서는 MUST NOT 안 된다. 수신자는 데이터그램의 첫 번째 패킷과 다른 Destination Connection ID를 가진 모든 후속 패킷을 무시해야 SHOULD 한다.

단일 UDP 데이터그램으로 병합된 모든 QUIC 패킷은 분리되어 있으며 완전하다. 병합된 QUIC 패킷의 수신자는 각 QUIC 패킷을 개별적으로 처리하고, 서로 다른 UDP 데이터그램의 페이로드로 수신된 것처럼 별도로 확인 응답해야 MUST 한다. 예를 들어 복호화가 실패하면(키를 사용할 수 없거나 다른 이유로), 수신자는 그 패킷을 폐기하거나 나중 처리를 위해 버퍼링할 수 MAY 있으며, 남은 패킷 처리를 시도해야 MUST 한다.

Retry 패킷(Section 17.2.5), Version Negotiation 패킷(Section 17.2.1), 및 짧은 헤더가 있는 패킷(Section 17.3)은 Length 필드를 포함하지 않으므로 같은 UDP 데이터그램에서 다른 패킷이 뒤따를 수 없다. 또한 Retry 또는 Version Negotiation 패킷이 다른 패킷과 병합되는 상황은 없다는 점에 유의한다.

12.3. 패킷 번호

패킷 번호는 0부터 262-1 범위의 정수이다. 이 번호는 패킷 보호를 위한 암호화 nonce를 결정하는 데 사용된다. 각 엔드포인트는 송신 및 수신을 위해 별도의 패킷 번호를 유지한다.

패킷 번호는 ACK 프레임(Section 19.3)의 Largest Acknowledged 필드에 전체로 표현될 수 있어야 하므로 이 범위로 제한된다. 그러나 긴 헤더나 짧은 헤더에 존재할 때, 패킷 번호는 줄어들고 1~4바이트로 인코딩된다. Section 17.1을 참조한다.

Version Negotiation(Section 17.2.1) 및 Retry(Section 17.2.5) 패킷은 패킷 번호를 포함하지 않는다.

QUIC에서 패킷 번호는 세 공간으로 나뉜다:

Initial 공간:

모든 Initial 패킷(Section 17.2.2)은 이 공간에 있다.

Handshake 공간:

모든 Handshake 패킷(Section 17.2.4)은 이 공간에 있다.

애플리케이션 데이터 공간:

모든 0-RTT(Section 17.2.3) 및 1-RTT(Section 17.3.1) 패킷은 이 공간에 있다.

[QUIC-TLS]에 설명된 것처럼, 각 패킷 유형은 서로 다른 보호 키를 사용한다.

개념적으로 패킷 번호 공간은 패킷을 처리하고 확인 응답할 수 있는 컨텍스트이다. Initial 패킷은 Initial 패킷 보호 키로만 보낼 수 있고, 역시 Initial 패킷인 패킷에서만 확인 응답될 수 있다. 마찬가지로, Handshake 패킷은 Handshake 암호화 수준에서 전송되며 Handshake 패킷에서만 확인 응답될 수 있다.

이는 서로 다른 패킷 번호 공간에서 전송되는 데이터 사이의 암호화적 분리를 강제한다. 각 공간의 패킷 번호는 패킷 번호 0에서 시작한다. 같은 패킷 번호 공간에서 이후 전송되는 패킷은 패킷 번호를 최소 1만큼 증가시켜야 MUST 한다.

0-RTT 및 1-RTT 데이터는 두 패킷 유형 사이에서 손실 복구 알고리즘을 더 쉽게 구현할 수 있도록 같은 패킷 번호 공간에 존재한다.

QUIC 엔드포인트는 하나의 연결에서 같은 패킷 번호 공간 안의 패킷 번호를 재사용해서는 MUST NOT 안 된다. 송신용 패킷 번호가 262-1에 도달하면, 송신자는 CONNECTION_CLOSE 프레임이나 추가 패킷을 보내지 않고 연결을 닫아야 MUST 한다. 엔드포인트는 이후 수신하는 패킷에 대한 응답으로 Stateless Reset(Section 10.3)을 보낼 수 MAY 있다.

수신자는 같은 패킷 번호 공간에서 같은 패킷 번호를 가진 다른 패킷을 처리하지 않았다는 것이 확실하지 않은 한, 새로 보호가 해제된 패킷을 폐기해야 MUST 한다. 중복 억제는 Section 9.5 of [QUIC-TLS]에 설명된 이유 때문에 패킷 보호를 제거한 후 수행되어야 MUST 한다.

중복 감지를 위해 모든 개별 패킷을 추적하는 엔드포인트는 과도한 상태를 축적할 위험이 있다. 중복 감지에 필요한 데이터는, 그보다 낮은 번호의 모든 패킷이 즉시 삭제되는 최소 패킷 번호를 유지하여 제한할 수 있다. 모든 최소값은 왕복 시간의 큰 변동을 고려해야 하며, 여기에는 피어가 훨씬 더 큰 왕복 시간을 가진 네트워크 경로를 탐색할 가능성도 포함된다. Section 9를 참조한다.

송신자의 패킷 번호 인코딩과 수신자의 디코딩은 Section 17.1에 설명되어 있다.

12.4. 프레임과 프레임 유형

패킷 보호를 제거한 후 QUIC 패킷의 페이로드는 Figure 11에 표시된 것처럼 완전한 프레임의 시퀀스로 구성된다. Version Negotiation, Stateless Reset 및 Retry 패킷은 프레임을 포함하지 않는다.

Packet Payload {
  Frame (8..) ...,
}
Figure 11: QUIC 페이로드

프레임을 포함하는 패킷의 페이로드는 최소 하나의 프레임을 포함해야 MUST 하며, 여러 프레임과 여러 프레임 유형을 포함할 수 MAY 있다. 엔드포인트는 프레임을 포함하지 않는 패킷의 수신을 PROTOCOL_VIOLATION 유형의 연결 오류로 처리해야 MUST 한다. 프레임은 항상 단일 QUIC 패킷 안에 들어가며 여러 패킷에 걸칠 수 없다.

각 프레임은 그 유형을 나타내는 Frame Type으로 시작하고, 그 뒤에 유형에 따라 달라지는 추가 필드가 이어진다:

Frame {
  Frame Type (i),
  Type-Dependent Fields (..),
}
Figure 12: 일반 프레임 레이아웃

Table 3은 이 명세에 정의된 각 프레임 유형에 대한 정보를 나열하고 요약한다. 이 요약에 대한 설명은 표 뒤에 포함되어 있다.

Table 3: 프레임 유형
유형 값 프레임 유형 이름 정의 Pkts Spec
0x00 PADDING Section 19.1 IH01 NP
0x01 PING Section 19.2 IH01
0x02-0x03 ACK Section 19.3 IH_1 NC
0x04 RESET_STREAM Section 19.4 __01
0x05 STOP_SENDING Section 19.5 __01
0x06 CRYPTO Section 19.6 IH_1
0x07 NEW_TOKEN Section 19.7 ___1
0x08-0x0f STREAM Section 19.8 __01 F
0x10 MAX_DATA Section 19.9 __01
0x11 MAX_STREAM_DATA Section 19.10 __01
0x12-0x13 MAX_STREAMS Section 19.11 __01
0x14 DATA_BLOCKED Section 19.12 __01
0x15 STREAM_DATA_BLOCKED Section 19.13 __01
0x16-0x17 STREAMS_BLOCKED Section 19.14 __01
0x18 NEW_CONNECTION_ID Section 19.15 __01 P
0x19 RETIRE_CONNECTION_ID Section 19.16 __01
0x1a PATH_CHALLENGE Section 19.17 __01 P
0x1b PATH_RESPONSE Section 19.18 ___1 P
0x1c-0x1d CONNECTION_CLOSE Section 19.19 ih01 N
0x1e HANDSHAKE_DONE Section 19.20 ___1

각 프레임 유형의 형식과 의미론은 Section 19에서 더 자세히 설명된다. 이 섹션의 나머지는 중요하고 일반적인 정보의 요약을 제공한다.

ACK, STREAM, MAX_STREAMS, STREAMS_BLOCKED 및 CONNECTION_CLOSE 프레임의 Frame Type은 다른 프레임별 플래그를 운반하는 데 사용된다. 다른 모든 프레임의 경우 Frame Type 필드는 단순히 프레임을 식별한다.

Table 3의 "Pkts" 열은 각 프레임 유형이 나타날 수 있는 패킷 유형을 나열하며, 다음 문자로 표시된다:

I:

Initial(Section 17.2.2)

H:

Handshake(Section 17.2.4)

0:

0-RTT(Section 17.2.3)

1:

1-RTT(Section 17.3.1)

ih:

type 0x1c의 CONNECTION_CLOSE 프레임만 Initial 또는 Handshake 패킷에 나타날 수 있다.

이러한 제한에 대한 자세한 내용은 Section 12.5를 참조한다. 모든 프레임은 1-RTT 패킷에 나타날 수 있음에 유의한다. 엔드포인트는 허용되지 않는 패킷 유형에서 프레임을 수신한 것을 PROTOCOL_VIOLATION 유형의 연결 오류로 처리해야 MUST 한다.

Table 3의 "Spec" 열은 다음 문자로 표시되는, 해당 프레임 유형의 처리 또는 생성에 적용되는 특수 규칙을 요약한다:

N:

이 표시가 있는 프레임만 포함하는 패킷은 ack-eliciting이 아니다. Section 13.2를 참조한다.

C:

이 표시가 있는 프레임만 포함하는 패킷은 혼잡 제어 목적의 비행 중 바이트에 포함되지 않는다. [QUIC-RECOVERY]를 참조한다.

P:

이 표시가 있는 프레임만 포함하는 패킷은 연결 마이그레이션 중 새 네트워크 경로를 탐색하는 데 사용할 수 있다. Section 9.1을 참조한다.

F:

이 표시가 있는 프레임의 내용은 흐름 제어를 받는다. Section 4를 참조한다.

Table 3의 "Pkts" 및 "Spec" 열은 IANA 레지스트리의 일부를 구성하지 않는다. Section 22.4를 참조한다.

엔드포인트는 알 수 없는 유형의 프레임 수신을 FRAME_ENCODING_ERROR 유형의 연결 오류로 처리해야 MUST 한다.

이 QUIC 버전의 모든 프레임은 멱등적이다. 즉, 유효한 프레임은 두 번 이상 수신되어도 바람직하지 않은 부작용이나 오류를 일으키지 않는다.

Frame Type 필드는 한 가지 예외를 제외하고 가변 길이 정수 인코딩 (Section 16 참조)을 사용한다. 프레임 파싱의 단순하고 효율적인 구현을 보장하기 위해, 프레임 유형은 가능한 가장 짧은 인코딩을 사용해야 MUST 한다. 이 문서에 정의된 프레임 유형의 경우, 이는 이 값들을 2바이트, 4바이트 또는 8바이트 가변 길이 정수로 인코딩할 수 있더라도 단일 바이트 인코딩을 의미한다. 예를 들어 0x4001은 값이 1인 가변 길이 정수의 정당한 2바이트 인코딩이지만, PING 프레임은 항상 값 0x01의 단일 바이트로 인코딩된다. 이 규칙은 현재와 향후의 모든 QUIC 프레임 유형에 적용된다. 엔드포인트는 필요한 것보다 긴 인코딩을 사용하는 프레임 유형의 수신을 PROTOCOL_VIOLATION 유형의 연결 오류로 처리할 수 MAY 있다.

12.5. 프레임과 번호 공간

일부 프레임은 서로 다른 패킷 번호 공간에서 금지된다. 여기의 규칙은 TLS의 규칙을 일반화한 것으로, 연결 설정과 관련된 프레임은 일반적으로 어떤 패킷 번호 공간의 패킷에도 나타날 수 있는 반면, 데이터 전송과 관련된 프레임은 애플리케이션 데이터 패킷 번호 공간에만 나타날 수 있다:

  • PADDING, PING 및 CRYPTO 프레임은 어떤 패킷 번호 공간에도 나타날 수 MAY 있다.
  • QUIC 계층의 오류를 신호하는 CONNECTION_CLOSE 프레임 (type 0x1c)은 어떤 패킷 번호 공간에도 나타날 수 MAY 있다. 애플리케이션 오류를 신호하는 CONNECTION_CLOSE 프레임 (type 0x1d)은 애플리케이션 데이터 패킷 번호 공간에만 나타나야 MUST 한다.
  • ACK 프레임은 어떤 패킷 번호 공간에도 나타날 수 MAY 있지만, 해당 패킷 번호 공간에 나타난 패킷만 확인 응답할 수 있다. 그러나 아래에 언급된 것처럼, 0-RTT 패킷은 ACK 프레임을 포함할 수 없다.
  • 다른 모든 프레임 유형은 애플리케이션 데이터 패킷 번호 공간에서만 전송되어야 MUST 한다.

다음 프레임은 여러 이유로 0-RTT 패킷에서 보낼 수 없음에 유의한다: ACK, CRYPTO, HANDSHAKE_DONE, NEW_TOKEN, PATH_RESPONSE 및 RETIRE_CONNECTION_ID. 서버는 0-RTT 패킷에서 이러한 프레임을 수신한 것을 PROTOCOL_VIOLATION 유형의 연결 오류로 처리할 수 MAY 있다.

13. 패킷화와 신뢰성

송신자는 QUIC 패킷에 하나 이상의 프레임을 보낸다. Section 12.4를 참조한다.

송신자는 각 QUIC 패킷에 가능한 한 많은 프레임을 포함하여 패킷당 대역폭 및 계산 비용을 최소화할 수 있다. 송신자는 많은 수의 작은 패킷이 전송되는 것을 피하기 위해, 최대로 채워지지 않은 패킷을 보내기 전에 여러 프레임을 모으려고 짧은 시간 동안 기다릴 수 MAY 있다. 구현은 애플리케이션 전송 동작에 대한 지식이나 휴리스틱을 사용하여 기다릴지 여부와 얼마나 오래 기다릴지를 결정할 수 MAY 있다. 이 대기 기간은 구현 결정이며, 지연은 애플리케이션에 보이는 지연 시간을 증가시킬 가능성이 높으므로 구현은 보수적으로 지연하도록 주의해야 한다.

스트림 다중화는 여러 스트림의 STREAM 프레임을 하나 이상의 QUIC 패킷에 인터리빙하여 달성된다. 단일 QUIC 패킷은 하나 이상의 스트림에서 온 여러 STREAM 프레임을 포함할 수 있다.

QUIC의 이점 중 하나는 여러 스트림에 걸친 head-of-line 차단을 피하는 것이다. 패킷 손실이 발생하면, 해당 패킷에 데이터가 있는 스트림만 재전송 수신을 기다리며 차단되고, 다른 스트림은 계속 진행할 수 있다. 단일 QUIC 패킷에 여러 스트림의 데이터가 포함된 경우, 그 패킷의 손실은 해당 모든 스트림의 진행을 차단한다는 점에 유의한다. 구현은 덜 채워진 패킷으로 인해 전송 효율을 잃지 않는 범위에서, 나가는 패킷에 필요한 만큼만 적은 수의 스트림을 포함하는 것이 권고된다.

13.1. 패킷 처리

패킷 보호가 성공적으로 제거되고 패킷에 포함된 모든 프레임이 처리되기 전에는 패킷에 확인 응답해서는 MUST NOT 안 된다. STREAM 프레임의 경우, 이는 데이터가 애플리케이션 프로토콜에 의해 수신될 준비로 큐에 들어갔음을 의미하지만, 데이터가 전달되고 소비되어야 함을 요구하지는 않는다.

패킷이 완전히 처리되면, 수신자는 수신한 패킷의 패킷 번호를 포함하는 하나 이상의 ACK 프레임을 보내 수신을 확인 응답한다.

엔드포인트는 조건을 감지할 수 있다면, 자신이 보내지 않은 패킷에 대한 확인 응답의 수신을 PROTOCOL_VIOLATION 유형의 연결 오류로 처리해야 SHOULD 한다. 이를 달성하는 방법에 대한 추가 논의는 Section 21.4를 참조한다.

13.2. 확인 응답 생성

엔드포인트는 자신이 수신하고 처리하는 모든 패킷에 확인 응답한다. 그러나 ack-eliciting 패킷만 최대 ack 지연 내에 ACK 프레임이 전송되게 한다. ack-eliciting이 아닌 패킷은 다른 이유로 ACK 프레임이 전송될 때만 확인 응답된다.

어떤 이유로든 패킷을 보낼 때, 엔드포인트는 최근에 ACK 프레임이 전송되지 않았다면 ACK 프레임을 포함하려고 시도해야 SHOULD 한다. 그렇게 하면 피어에서 적시에 손실을 감지하는 데 도움이 된다.

일반적으로 수신자의 빈번한 피드백은 손실 및 혼잡 대응을 개선하지만, 이는 모든 ack-eliciting 패킷에 대한 응답으로 ACK 프레임을 보내는 수신자가 생성하는 과도한 부하와 균형을 이루어야 한다. 아래에 제공되는 지침은 이 균형을 맞추려 한다.

13.2.1. ACK 프레임 보내기

모든 패킷은 최소 한 번 확인 응답되어야 SHOULD 하며, ack-eliciting 패킷은 엔드포인트가 max_ack_delay 전송 매개변수를 사용해 전달한 최대 지연 내에 최소 한 번 확인 응답되어야 MUST 한다. Section 18.2를 참조한다. max_ack_delay는 명시적인 계약을 선언한다. 즉, 엔드포인트는 ack-eliciting 패킷의 확인 응답을 표시된 값보다 더 오래 의도적으로 지연하지 않겠다고 약속한다. 그렇게 하면 초과분이 RTT 추정치에 누적되어 피어의 허위 또는 지연된 재전송을 초래할 수 있다. 송신자는 타이머 기반 재전송을 위한 타임아웃을 결정할 때 수신자의 max_ack_delay 값을 사용한다. 자세한 내용은 Section 6.2 of [QUIC-RECOVERY]에 있다.

엔드포인트는 모든 ack-eliciting Initial 및 Handshake 패킷에 즉시, 그리고 모든 ack-eliciting 0-RTT 및 1-RTT 패킷에 자신의 광고된 max_ack_delay 내에 확인 응답해야 MUST 하며, 다음 예외가 있다. 핸드셰이크 확인 전에, 엔드포인트는 Handshake, 0-RTT 또는 1-RTT 패킷을 수신할 때 이를 복호화할 패킷 보호 키를 가지고 있지 않을 수 있다. 따라서 엔드포인트는 이를 버퍼링하고 필요한 키를 사용할 수 있게 되면 확인 응답할 수 있다.

ACK 프레임만 포함하는 패킷은 혼잡 제어를 받지 않으므로, 엔드포인트는 ack-eliciting 패킷을 수신한 것에 대한 응답으로 그러한 패킷을 둘 이상 보내서는 MUST NOT 안 된다.

엔드포인트는 수신한 패킷보다 앞선 패킷 간격이 있더라도, ack-eliciting이 아닌 패킷에 대한 응답으로 ack-eliciting이 아닌 패킷을 보내서는 MUST NOT 안 된다. 이는 확인 응답의 무한 피드백 루프를 피하며, 그런 루프는 연결이 결코 유휴 상태가 되지 못하게 할 수 있다. ack-eliciting이 아닌 패킷은 엔드포인트가 다른 이벤트에 대한 응답으로 ACK 프레임을 보낼 때 결국 확인 응답된다.

ACK 프레임만 보내는 엔드포인트는 그 확인 응답이 ack-eliciting 프레임이 있는 패킷에 포함되지 않는 한 피어로부터 확인 응답을 받지 못한다. 확인 응답할 새 ack-eliciting 패킷이 있을 때 엔드포인트는 다른 프레임과 함께 ACK 프레임을 보내야 SHOULD 한다. ack-eliciting이 아닌 패킷만 확인 응답해야 하는 경우, 엔드포인트는 ack-eliciting 패킷을 수신할 때까지 나가는 프레임과 함께 ACK 프레임을 보내지 않기로 선택할 수 MAY 있다.

ack-eliciting이 아닌 패킷만 보내는 엔드포인트는 확인 응답을 수신하도록 보장하기 위해 때때로 이러한 패킷에 ack-eliciting 프레임을 추가하기로 선택할 수 있다. Section 13.2.4를 참조한다. 이 경우, 엔드포인트는 원래라면 ack-eliciting이 아닌 모든 패킷에 ack-eliciting 프레임을 보내서는 MUST NOT 안 된다. 확인 응답의 무한 피드백 루프를 피하기 위해서이다.

송신자의 손실 감지를 돕기 위해, 엔드포인트는 ack-eliciting 패킷을 수신할 때 다음 중 하나에 해당하면 지연 없이 ACK 프레임을 생성하고 보내야 SHOULD 한다:

  • 수신한 패킷의 패킷 번호가 이미 수신된 다른 ack-eliciting 패킷보다 작은 경우, 또는
  • 패킷의 패킷 번호가 수신된 가장 큰 번호의 ack-eliciting 패킷보다 크고, 그 패킷과 이 패킷 사이에 누락된 패킷이 있는 경우.

마찬가지로, IP 헤더에서 ECN Congestion Experienced(CE) 코드포인트로 표시된 패킷은 혼잡 이벤트에 대한 피어의 응답 시간을 줄이기 위해 즉시 확인 응답되어야 SHOULD 한다.

[QUIC-RECOVERY]의 알고리즘은 위에서 제공한 지침을 따르지 않는 수신자에도 견고할 것으로 기대된다. 그러나 구현은 엔드포인트가 만든 연결과 네트워크의 다른 사용자에 대한 변경의 성능 영향을 신중히 고려한 후에만 이러한 요구사항에서 벗어나야 한다.

13.2.2. 확인 응답 빈도

수신자는 ack-eliciting 패킷에 대한 응답으로 얼마나 자주 확인 응답을 보낼지 결정한다. 이 결정에는 트레이드오프가 수반된다.

엔드포인트는 손실을 감지하기 위해 적시의 확인 응답에 의존한다. Section 6 of [QUIC-RECOVERY]을 참조한다. Section 7 of [QUIC-RECOVERY]에 설명된 것과 같은 윈도우 기반 혼잡 제어기는 혼잡 윈도우를 관리하기 위해 확인 응답에 의존한다. 두 경우 모두 확인 응답을 지연하면 성능에 악영향을 줄 수 있다.

반면, 확인 응답만 운반하는 패킷의 빈도를 줄이면 양쪽 엔드포인트의 패킷 전송 및 처리 비용이 줄어든다. 이는 심하게 비대칭인 링크에서 연결 처리량을 개선하고 반환 경로 용량을 사용하는 확인 응답 트래픽의 양을 줄일 수 있다. Section 3 of [RFC3449]를 참조한다.

수신자는 최소 두 개의 ack-eliciting 패킷을 수신한 후 ACK 프레임을 보내야 SHOULD 한다. 이 권고는 일반적인 성격을 가지며 TCP 엔드포인트 동작에 대한 권고 [RFC5681]와 일치한다. 네트워크 조건에 대한 지식, 피어의 혼잡 제어기에 대한 지식, 또는 추가 연구와 실험은 더 나은 성능 특성을 가진 대체 확인 응답 전략을 제안할 수 있다.

수신자는 응답으로 ACK 프레임을 보낼지 결정하기 전에 사용 가능한 여러 패킷을 처리할 수 MAY 있다.

13.2.3. ACK 범위 관리

ACK 프레임이 전송될 때, 확인 응답된 패킷의 하나 이상의 범위가 포함된다. 오래된 패킷에 대한 확인 응답을 포함하면, 이전에 보낸 ACK 프레임의 손실로 인한 허위 재전송 가능성을 줄이지만, ACK 프레임이 커지는 비용이 따른다.

ACK 프레임은 항상 가장 최근에 수신한 패킷을 확인 응답해야 SHOULD 하며, 패킷이 순서를 벗어난 정도가 클수록 피어가 패킷을 손실된 것으로 선언하고 그 안에 포함된 프레임을 허위로 재전송하는 것을 막기 위해 업데이트된 ACK 프레임을 빠르게 보내는 것이 더 중요하다. ACK 프레임은 단일 QUIC 패킷 안에 들어갈 것으로 기대된다. 그렇지 않으면 오래된 범위 (가장 작은 패킷 번호를 가진 범위)가 생략된다.

수신자는 ACK 프레임의 크기를 제한하고 리소스 고갈을 피하기 위해, 자신이 기억하고 ACK 프레임으로 보내는 ACK Range(Section 19.3.1)의 수를 제한한다. ACK 프레임에 대한 확인 응답을 수신한 후, 수신자는 해당 확인 응답된 ACK Range의 추적을 중단해야 SHOULD 한다. 송신자는 대부분의 패킷에 대한 확인 응답을 기대할 수 있지만, QUIC는 수신자가 처리하는 모든 패킷에 대한 확인 응답 수신을 보장하지 않는다.

많은 ACK Range를 유지하면 ACK 프레임이 너무 커질 수 있다. 수신자는 ACK 프레임 크기를 제한하기 위해 확인 응답되지 않은 ACK Range를 폐기할 수 있으며, 그 대가로 송신자의 재전송이 증가할 수 있다. 이는 ACK 프레임이 패킷에 들어가기 너무 큰 경우 필요하다. 수신자는 다른 프레임을 위한 공간을 보존하거나 확인 응답이 소비하는 용량을 제한하기 위해 ACK 프레임 크기를 더 제한할 수도 MAY 있다.

수신자는 해당 범위의 번호를 가진 패킷을 이후에 수락하지 않을 것임을 보장할 수 없는 한 ACK Range를 유지해야 MUST 한다. 범위가 폐기될 때 증가하는 최소 패킷 번호를 유지하는 것은 최소 상태로 이를 달성하는 한 가지 방법이다.

수신자는 모든 ACK Range를 폐기할 수 있지만, 이후 패킷에서 패킷 번호를 복구하는 데 사용되므로 성공적으로 처리된 가장 큰 패킷 번호는 유지해야 MUST 한다. Section 17.1을 참조한다.

수신자는 모든 ACK 프레임에 가장 큰 수신 패킷 번호를 포함하는 ACK Range를 포함해야 SHOULD 한다. Largest Acknowledged 필드는 송신자에서 ECN 검증에 사용되며, 이전 ACK 프레임에 포함된 값보다 낮은 값을 포함하면 ECN이 불필요하게 비활성화될 수 있다. Section 13.4.2를 참조한다.

Section 13.2.4는 각 ACK 프레임에서 어떤 패킷을 확인 응답할지 결정하는 예시적인 접근 방식을 설명한다. 이 알고리즘의 목표가 처리되는 모든 패킷에 대한 확인 응답을 생성하는 것이더라도, 확인 응답이 손실될 가능성은 여전히 있다.

13.2.4. ACK 프레임 추적으로 범위 제한

ACK 프레임을 포함하는 패킷이 전송될 때, 해당 프레임의 Largest Acknowledged 필드를 저장할 수 있다. ACK 프레임을 포함하는 패킷이 확인 응답되면, 수신자는 전송된 ACK 프레임의 Largest Acknowledged 필드보다 작거나 같은 패킷에 대한 확인 응답을 중단할 수 있다.

ACK 프레임과 같이 ack-eliciting이 아닌 패킷만 보내는 수신자는 오랜 시간 동안 확인 응답을 받지 못할 수 있다. 이는 수신자가 많은 수의 ACK 프레임에 대한 상태를 오랜 시간 유지하게 만들 수 있으며, 수신자가 보내는 ACK 프레임이 불필요하게 커질 수 있다. 이러한 경우 수신자는 피어로부터 ACK를 유도하기 위해, 예를 들어 왕복마다 한 번씩, 때때로 PING 또는 다른 작은 ack-eliciting 프레임을 보낼 수 있다.

ACK 프레임 손실이 없는 경우, 이 알고리즘은 최소 1 RTT의 재정렬을 허용한다. ACK 프레임 손실과 재정렬이 있는 경우, 이 접근 방식은 모든 확인 응답이 ACK 프레임에 더 이상 포함되지 않기 전에 송신자에게 보이는 것을 보장하지 않는다. 패킷은 순서를 벗어나 수신될 수 있고, 이를 포함하는 모든 후속 ACK 프레임이 손실될 수 있다. 이 경우 손실 복구 알고리즘은 허위 재전송을 일으킬 수 있지만, 송신자는 계속 전진한다.

13.2.5. 호스트 지연 측정 및 보고

엔드포인트는 가장 큰 패킷 번호를 가진 패킷이 수신된 시점과 확인 응답이 전송된 시점 사이에 의도적으로 도입된 지연을 측정한다. 엔드포인트는 이 확인 응답 지연을 ACK 프레임의 ACK Delay 필드에 인코딩한다. Section 19.3을 참조한다. 이는 ACK 프레임의 수신자가 의도적인 지연을 보정할 수 있게 하며, 확인 응답이 지연될 때 경로 RTT의 더 나은 추정치를 얻는 데 중요하다.

패킷은 처리되기 전에 OS 커널이나 호스트의 다른 위치에 머물러 있을 수 있다. 엔드포인트는 ACK 프레임의 ACK Delay 필드를 채울 때 자신이 제어하지 않는 지연을 포함해서는 MUST NOT 안 된다. 그러나 엔드포인트는 복호화 키를 사용할 수 없어 발생한 버퍼링 지연을 포함해야 SHOULD 한다. 이러한 지연은 클 수 있고 반복되지 않을 가능성이 높기 때문이다.

측정된 확인 응답 지연이 자신의 max_ack_delay보다 큰 경우, 엔드포인트는 측정된 지연을 보고해야 SHOULD 한다. 이 정보는 지연이 클 수 있는 핸드셰이크 중 특히 유용하다. Section 13.2.1을 참조한다.

13.2.6. ACK 프레임과 패킷 보호

ACK 프레임은 확인 응답되는 패킷과 같은 패킷 번호 공간을 가진 패킷에만 운반되어야 MUST 한다. Section 12.1을 참조한다. 예를 들어, 1-RTT 키로 보호된 패킷은 역시 1-RTT 키로 보호된 패킷에서 확인 응답되어야 MUST 한다.

클라이언트가 0-RTT 패킷 보호로 보내는 패킷은 서버가 1-RTT 키로 보호된 패킷에서 확인 응답해야 MUST 한다. 이는 서버의 암호화 핸드셰이크 메시지가 지연되거나 손실되면 클라이언트가 이러한 확인 응답을 사용할 수 없음을 의미할 수 있다. 같은 제한은 1-RTT 키로 보호되어 서버가 보내는 다른 데이터에도 적용된다는 점에 유의한다.

13.2.7. PADDING 프레임은 혼잡 윈도우를 소비한다

PADDING 프레임을 포함하는 패킷은 혼잡 제어 목적상 비행 중인 것으로 간주된다 [QUIC-RECOVERY]. 따라서 PADDING 프레임만 포함하는 패킷은 혼잡 윈도우를 소비하지만 혼잡 윈도우를 열 확인 응답을 생성하지 않는다. 교착 상태를 피하기 위해, 송신자는 수신자로부터 확인 응답을 유도하도록 PADDING 프레임 외에 다른 프레임도 주기적으로 전송되도록 보장해야 SHOULD 한다.

13.3. 정보의 재전송

손실된 것으로 판단된 QUIC 패킷은 전체가 재전송되지 않는다. 손실된 패킷 안에 포함된 프레임에도 같은 원칙이 적용된다. 대신 프레임에 운반될 수 있었던 정보는 필요에 따라 새 프레임으로 다시 전송된다.

손실된 것으로 판단된 정보를 운반하기 위해 새 프레임과 패킷이 사용된다. 일반적으로 해당 정보를 포함하는 패킷이 손실된 것으로 판단되면 정보가 다시 전송되고, 해당 정보를 포함하는 패킷이 확인 응답되면 전송이 중단된다.

  • CRYPTO 프레임으로 전송된 데이터는 모든 데이터가 확인 응답될 때까지 [QUIC-RECOVERY]의 규칙에 따라 재전송된다. Initial 및 Handshake 패킷용 CRYPTO 프레임의 데이터는 해당 패킷 번호 공간의 키가 폐기될 때 폐기된다.
  • STREAM 프레임으로 전송된 애플리케이션 데이터는 엔드포인트가 해당 스트림에 대해 RESET_STREAM을 보낸 경우를 제외하고 새 STREAM 프레임으로 재전송된다. 엔드포인트가 RESET_STREAM 프레임을 보내면 더 이상의 STREAM 프레임은 필요하지 않다.
  • ACK 프레임은 Section 13.2.1에 설명된 것처럼 가장 최근의 확인 응답 집합과 가장 큰 확인 응답된 패킷으로부터의 확인 응답 지연을 운반한다. ACK 프레임을 포함하는 패킷의 전송을 지연하거나 오래된 ACK 프레임을 다시 보내면, 피어가 부풀려진 RTT 샘플을 생성하거나 ECN을 불필요하게 비활성화할 수 있다.
  • RESET_STREAM 프레임에 운반되는 스트림 전송 취소는 확인 응답될 때까지 또는 모든 스트림 데이터가 피어에 의해 확인 응답될 때까지 (즉, 스트림의 송신 부분에서 "Reset Recvd" 또는 "Data Recvd" 상태에 도달할 때까지) 전송된다. RESET_STREAM 프레임의 내용은 다시 전송될 때 변경되어서는 MUST NOT 안 된다.
  • 마찬가지로, STOP_SENDING 프레임으로 인코딩된 스트림 전송 취소 요청은 스트림의 수신 부분이 "Data Recvd" 또는 "Reset Recvd" 상태에 들어갈 때까지 전송된다. Section 3.5를 참조한다.
  • CONNECTION_CLOSE 프레임을 포함하는 패킷을 비롯한 연결 닫기 신호는 패킷 손실이 감지될 때 다시 전송되지 않는다. 이러한 신호를 다시 보내는 것은 Section 10에 설명되어 있다.
  • 현재 연결 최대 데이터는 MAX_DATA 프레임으로 전송된다. 가장 최근에 전송된 MAX_DATA 프레임을 포함하는 패킷이 손실된 것으로 선언되거나 엔드포인트가 한도를 업데이트하기로 결정하면, 업데이트된 값이 MAX_DATA 프레임으로 전송된다. 한도는 자주 증가할 수 있고 불필요하게 많은 MAX_DATA 프레임이 전송되도록 만들 수 있으므로, 이 프레임을 너무 자주 보내지 않도록 주의해야 한다. Section 4.2를 참조한다.
  • 현재 최대 스트림 데이터 오프셋은 MAX_STREAM_DATA 프레임으로 전송된다. MAX_DATA와 마찬가지로, 스트림에 대한 가장 최근의 MAX_STREAM_DATA 프레임을 포함하는 패킷이 손실되거나 한도가 업데이트되면 업데이트된 값이 전송되며, 프레임이 너무 자주 전송되지 않도록 주의한다. 엔드포인트는 스트림의 수신 부분이 "Size Known" 또는 "Reset Recvd" 상태에 들어가면 MAX_STREAM_DATA 프레임 전송을 중단해야 SHOULD 한다.
  • 주어진 유형의 스트림에 대한 한도는 MAX_STREAMS 프레임으로 전송된다. MAX_DATA와 마찬가지로, 스트림 유형에 대한 가장 최근의 MAX_STREAMS 프레임을 포함하는 패킷이 손실된 것으로 선언되거나 한도가 업데이트되면 업데이트된 값이 전송되며, 프레임이 너무 자주 전송되지 않도록 주의한다.
  • 차단 신호는 DATA_BLOCKED, STREAM_DATA_BLOCKED 및 STREAMS_BLOCKED 프레임으로 운반된다. DATA_BLOCKED 프레임은 연결 범위를 가지며, STREAM_DATA_BLOCKED 프레임은 스트림 범위를 가지고, STREAMS_BLOCKED 프레임은 특정 스트림 유형에 범위가 지정된다. 어떤 범위에 대한 가장 최근 프레임을 포함하는 패킷이 손실되면 새 프레임이 전송되지만, 엔드포인트가 해당 한도에서 차단되어 있는 동안에만 전송된다. 이러한 프레임은 항상 전송 시점에 차단을 일으키는 한도를 포함한다.
  • PATH_CHALLENGE 프레임을 사용하는 활성 여부 또는 경로 검증 검사는 일치하는 PATH_RESPONSE 프레임이 수신될 때까지 또는 활성 여부나 경로 검증 검사가 더 이상 필요하지 않을 때까지 주기적으로 전송된다. PATH_CHALLENGE 프레임은 전송될 때마다 서로 다른 페이로드를 포함한다.
  • PATH_RESPONSE 프레임을 사용하는 경로 검증 응답은 한 번만 전송된다. 피어는 추가 PATH_RESPONSE 프레임을 유도하기 위해 필요에 따라 더 많은 PATH_CHALLENGE 프레임을 보낼 것으로 예상된다.
  • 새 연결 ID는 NEW_CONNECTION_ID 프레임으로 전송되며, 이를 포함하는 패킷이 손실되면 재전송된다. 이 프레임의 재전송은 같은 시퀀스 번호 값을 운반한다. 마찬가지로 폐기된 연결 ID는 RETIRE_CONNECTION_ID 프레임으로 전송되며, 이를 포함하는 패킷이 손실되면 재전송된다.
  • NEW_TOKEN 프레임은 이를 포함하는 패킷이 손실되면 재전송된다. 프레임 내용의 직접 비교 외에는 재정렬되거나 중복된 NEW_TOKEN 프레임을 감지하기 위한 특별한 지원은 제공되지 않는다.
  • PING 및 PADDING 프레임은 정보를 포함하지 않으므로, 손실된 PING 또는 PADDING 프레임은 복구가 필요하지 않다.
  • HANDSHAKE_DONE 프레임은 확인 응답될 때까지 재전송되어야 MUST 한다.

애플리케이션이 지정한 우선순위가 달리 나타내지 않는 한, 엔드포인트는 새 데이터를 보내는 것보다 데이터 재전송을 우선해야 SHOULD 한다. Section 2.3을 참조한다.

송신자가 패킷을 보낼 때마다 최신 정보를 포함하는 프레임을 조립하는 것이 권장되지만, 손실된 패킷의 프레임 복사본을 재전송하는 것이 금지되지는 않는다. 프레임 복사본을 재전송하는 송신자는 패킷 번호 길이, 연결 ID 길이 및 경로 MTU의 변경으로 사용 가능한 페이로드 크기가 줄어드는 경우를 처리해야 한다. 수신자는 오래된 패킷에서 발견된 값보다 작은 최대 데이터 값을 운반하는 MAX_DATA 프레임과 같은 오래된 프레임을 포함하는 패킷을 수락해야 MUST 한다.

송신자는 패킷이 확인 응답된 후 해당 패킷의 정보를 재전송하는 것을 피해야 SHOULD 한다. 여기에는 손실된 것으로 선언된 후 확인 응답되는 패킷도 포함되며, 이는 네트워크 재정렬이 있을 때 발생할 수 있다. 이를 위해서는 송신자가 패킷이 손실된 것으로 선언된 후에도 패킷에 대한 정보를 유지해야 한다. 송신자는 PTO(Section 6.2 of [QUIC-RECOVERY])와 같이 재정렬을 충분히 허용하는 시간이 지난 후, 또는 메모리 한도에 도달하는 것과 같은 다른 이벤트를 기준으로 이 정보를 폐기할 수 있다.

손실을 감지하면 송신자는 적절한 혼잡 제어 조치를 취해야 MUST 한다. 손실 감지 및 혼잡 제어의 세부사항은 [QUIC-RECOVERY]에 설명되어 있다.

13.4. 명시적 혼잡 알림

QUIC 엔드포인트는 네트워크 혼잡을 감지하고 이에 대응하기 위해 ECN [RFC3168]을 사용할 수 있다. ECN은 엔드포인트가 IP 패킷의 ECN 필드에 ECN-Capable Transport(ECT) 코드포인트를 설정할 수 있게 한다. 그러면 네트워크 노드는 패킷을 삭제하는 대신 ECN 필드에 ECN-CE 코드포인트를 설정하여 혼잡을 나타낼 수 있다 [RFC8087]. 엔드포인트는 [QUIC-RECOVERY]에 설명된 대로, 보고된 혼잡에 대응해 전송 속도를 줄인다.

ECN을 활성화하기 위해, 송신 QUIC 엔드포인트는 먼저 경로가 ECN 표시를 지원하는지와 피어가 수신한 IP 헤더의 ECN 값을 보고하는지 판단한다. Section 13.4.2를 참조한다.

13.4.1. ECN 카운트 보고

ECN 사용은 수신 엔드포인트가 IP 패킷에서 ECN 필드를 읽을 것을 요구하지만, 모든 플랫폼에서 가능한 것은 아니다. 엔드포인트가 ECN 지원을 구현하지 않거나 수신한 ECN 필드에 접근할 수 없다면, 자신이 수신한 패킷에 대한 ECN 카운트를 보고하지 않는다.

엔드포인트가 자신이 보내는 패킷에 ECT 필드를 설정하지 않더라도, 접근 가능한 경우 수신한 ECN 표시에 대한 피드백을 제공해야 MUST 한다. ECN 카운트를 보고하지 않으면 송신자는 이 연결에 대해 ECN 사용을 비활성화하게 된다.

ECT(0), ECT(1) 또는 ECN-CE 코드포인트가 있는 IP 패킷을 수신하면, ECN이 활성화된 엔드포인트는 ECN 필드에 접근하고 해당 ECT(0), ECT(1) 또는 ECN-CE 카운트를 증가시킨다. 이러한 ECN 카운트는 이후 ACK 프레임에 포함된다. Sections 13.219.3을 참조한다.

각 패킷 번호 공간은 별도의 확인 응답 상태와 별도의 ECN 카운트를 유지한다. 병합된 QUIC 패킷(Section 12.2 참조)은 같은 IP 헤더를 공유하므로 ECN 카운트는 병합된 각 QUIC 패킷마다 한 번씩 증가한다.

예를 들어 Initial, Handshake 및 1-RTT QUIC 패킷이 각각 하나씩 단일 UDP 데이터그램으로 병합되면, 세 패킷 번호 공간 모두의 ECN 카운트는 단일 IP 헤더의 ECN 필드를 기준으로 각각 하나씩 증가한다.

ECN 카운트는 수신한 IP 패킷의 QUIC 패킷이 처리될 때만 증가한다. 따라서 중복 QUIC 패킷은 처리되지 않으며 ECN 카운트를 증가시키지 않는다. 관련 보안 우려 사항은 Section 21.10을 참조한다.

13.4.2. ECN 검증

결함 있는 네트워크 장치가 0이 아닌 ECN 코드포인트를 운반하는 패킷을 손상시키거나 잘못 삭제할 수 있다. 이러한 장치가 있는 상황에서도 연결성을 보장하기 위해, 엔드포인트는 각 네트워크 경로의 ECN 카운트를 검증하고 오류가 감지되면 해당 경로에서 ECN 사용을 비활성화한다.

새 경로에 대해 ECN 검증을 수행하려면:

  • 엔드포인트는 새 경로에서 피어에게 보내는 초기 나가는 패킷의 IP 헤더에 ECT(0) 코드포인트를 설정한다 [RFC8311].
  • 엔드포인트는 ECT 코드포인트로 전송된 모든 패킷이 결국 손실된 것으로 간주되는지 (Section 6 of [QUIC-RECOVERY]) 모니터링하며, 이는 ECN 검증이 실패했음을 나타낸다.

엔드포인트가 ECT 코드포인트가 있는 IP 패킷이 결함 있는 네트워크 요소에 의해 삭제될 수 있다고 예상할 근거가 있다면, 엔드포인트는 한 경로에서 처음 열 개의 나가는 패킷에만 또는 세 PTO 기간 동안 (Section 6.2 of [QUIC-RECOVERY] 참조) ECT 코드포인트를 설정할 수 있다. 0이 아닌 ECN 코드포인트로 표시된 모든 패킷이 이후 손실되면, 표시가 손실을 일으켰다는 가정하에 표시를 비활성화할 수 있다.

따라서 엔드포인트는 ECN 사용을 시도하고, 각 새 연결, 서버의 선호 주소로 전환할 때, 그리고 새 경로로 능동적 연결 마이그레이션할 때 이를 검증한다. Appendix A.4는 한 가지 가능한 알고리즘을 설명한다.

ECN 지원을 위해 경로를 탐색하는 다른 방법도 가능하며, 다른 표시 전략도 가능하다. 구현은 RFC에 정의된 다른 방법을 사용할 수 MAY 있다. [RFC8311]을 참조한다. ECT(1) 코드포인트를 사용하는 구현은 보고된 ECT(1) 카운트를 사용하여 ECN 검증을 수행해야 한다.

13.4.2.1. ECN 카운트가 있는 ACK 프레임 수신

네트워크에 의한 ECN-CE 표시의 잘못된 적용은 연결 성능 저하를 초래할 수 있다. 따라서 ECN 카운트가 있는 ACK 프레임을 수신한 엔드포인트는 이를 사용하기 전에 카운트를 검증한다. 엔드포인트는 새로 수신한 카운트를 마지막으로 성공적으로 처리된 ACK 프레임의 카운트와 비교하여 이 검증을 수행한다. ECN 카운트의 모든 증가는 ACK 프레임에서 새로 확인 응답된 패킷에 적용되었던 ECN 표시를 기준으로 검증된다.

ACK 프레임이 엔드포인트가 ECT(0) 또는 ECT(1) 코드포인트를 설정하여 보낸 패킷을 새로 확인 응답하는 경우, 해당 ECN 카운트가 ACK 프레임에 존재하지 않으면 ECN 검증은 실패한다. 이 검사는 ECN 필드를 0으로 만드는 네트워크 요소나 ECN 표시를 보고하지 않는 피어를 감지한다.

ECT(0) 및 ECN-CE 카운트 증가의 합이 원래 ECT(0) 표시로 전송된 새로 확인 응답된 패킷 수보다 작아도 ECN 검증은 실패한다. 마찬가지로, ECT(1) 및 ECN-CE 카운트 증가의 합이 ECT(1) 표시로 전송된 새로 확인 응답된 패킷 수보다 작으면 ECN 검증은 실패한다. 이러한 검사는 네트워크에 의한 ECN-CE 표시의 재표시를 감지할 수 있다.

ACK 프레임이 손실될 때 엔드포인트는 패킷에 대한 확인 응답을 놓칠 수 있다. 따라서 ECT(0), ECT(1) 및 ECN-CE 카운트의 총 증가가 ACK 프레임에 의해 새로 확인 응답된 패킷 수보다 클 수 있다. 이것이 ECN 카운트가 확인 응답된 총 패킷 수보다 더 클 수 있도록 허용되는 이유이다.

재정렬된 ACK 프레임에서 ECN 카운트를 검증하면 실패가 발생할 수 있다. 엔드포인트는 가장 큰 확인 응답된 패킷 번호를 증가시키지 않는 ACK 프레임을 처리한 결과로 ECN 검증을 실패시켜서는 MUST NOT 안 된다.

ECT(0) 또는 ECT(1)의 수신 총 카운트가 각각 해당 ECT 코드포인트로 전송된 총 패킷 수를 초과하면 ECN 검증은 실패할 수 있다. 특히 엔드포인트가 전혀 적용한 적 없는 ECT 코드포인트에 해당하는 0이 아닌 ECN 카운트를 수신하면 검증은 실패한다. 이 검사는 패킷이 네트워크에서 ECT(0) 또는 ECT(1)로 재표시되는 경우를 감지한다.

13.4.2.2. ECN 검증 결과

검증이 실패하면 엔드포인트는 ECN을 비활성화해야 MUST 한다. 엔드포인트는 네트워크 경로나 피어가 ECN을 지원하지 않는다고 가정하고, 자신이 보내는 IP 패킷에 ECT 코드포인트 설정을 중단한다.

검증이 실패하더라도, 엔드포인트는 연결의 이후 어느 시점에든 같은 경로에 대해 ECN을 재검증할 수 MAY 있다. 엔드포인트는 주기적으로 검증 시도를 계속할 수 있다.

검증이 성공하면, 엔드포인트는 경로가 ECN 가능하다는 기대 하에 이후 자신이 보내는 패킷에 ECT 코드포인트를 계속 설정할 수 MAY 있다. 네트워크 라우팅과 경로 요소는 연결 중간에 변경될 수 있다. 이후 검증이 실패하면 엔드포인트는 ECN을 비활성화해야 MUST 한다.

14. 데이터그램 크기

UDP 데이터그램은 하나 이상의 QUIC 패킷을 포함할 수 있다. 데이터그램 크기는 QUIC 패킷을 운반하는 단일 UDP 데이터그램의 전체 UDP 페이로드 크기를 가리킨다. 데이터그램 크기에는 하나 이상의 QUIC 패킷 헤더와 보호된 페이로드가 포함되지만, UDP 또는 IP 헤더는 포함되지 않는다.

최대 데이터그램 크기는 단일 UDP 데이터그램을 사용하여 네트워크 경로를 통해 전송할 수 있는 UDP 페이로드의 가장 큰 크기로 정의된다. 네트워크 경로가 최소 1200바이트의 최대 데이터그램 크기를 지원할 수 없다면 QUIC를 사용해서는 MUST NOT 안 된다.

QUIC는 최소 IP 패킷 크기가 최소 1280바이트라고 가정한다. 이는 IPv6 최소 크기 [IPv6]이며, 대부분의 최신 IPv4 네트워크에서도 지원된다. IPv6의 최소 IP 헤더 크기를 40바이트, IPv4의 최소 IP 헤더 크기를 20바이트, UDP 헤더 크기를 8바이트로 가정하면, IPv6의 최대 데이터그램 크기는 1232바이트이고 IPv4의 최대 데이터그램 크기는 1252바이트가 된다. 따라서 최신 IPv4와 모든 IPv6 네트워크 경로는 QUIC를 지원할 수 있을 것으로 기대된다.

1200바이트보다 큰 모든 최대 데이터그램 크기는 Path Maximum Transmission Unit Discovery(PMTUD)(Section 14.2.1 참조) 또는 Datagram Packetization Layer PMTU Discovery(DPLPMTUD)(Section 14.3 참조)를 사용하여 발견할 수 있다.

max_udp_payload_size 전송 매개변수 (Section 18.2)의 적용은 최대 데이터그램 크기에 대한 추가 한도로 작용할 수 있다. 송신자는 값이 알려지면 이 한도를 초과하지 않도록 할 수 있다. 그러나 전송 매개변수 값을 알기 전에는, 엔드포인트가 허용되는 가장 작은 최대 데이터그램 크기인 1200바이트보다 큰 데이터그램을 보내면 데이터그램이 손실될 위험이 있다.

UDP 데이터그램은 IP 계층에서 조각화되어서는 MUST NOT 안 된다. IPv4 [IPv4]에서는 경로상 조각화를 방지하기 위해 가능하다면 Don't Fragment(DF) 비트를 설정해야 MUST 한다.

QUIC는 때때로 데이터그램이 특정 크기보다 작지 않을 것을 요구한다. 예로 Section 8.1을 참조한다. 그러나 데이터그램의 크기는 인증되지 않는다. 즉, 엔드포인트가 특정 크기의 데이터그램을 수신하더라도 송신자가 같은 크기로 데이터그램을 보냈는지 알 수 없다. 따라서 엔드포인트는 크기 제약을 충족하지 않는 데이터그램을 수신했을 때 연결을 닫아서는 MUST NOT 안 된다. 엔드포인트는 그러한 데이터그램을 폐기할 수 MAY 있다.

14.1. Initial 데이터그램 크기

클라이언트는 Initial 패킷에 PADDING 프레임을 추가하거나 Initial 패킷을 병합하여(Section 12.2 참조) Initial 패킷을 운반하는 모든 UDP 데이터그램의 페이로드를 허용되는 가장 작은 최대 데이터그램 크기인 최소 1200바이트로 확장해야 MUST 한다. Initial 패킷은 수신자가 폐기할 유효하지 않은 패킷과도 병합될 수 있다. 마찬가지로 서버는 ack-eliciting Initial 패킷을 운반하는 모든 UDP 데이터그램의 페이로드를 허용되는 가장 작은 최대 데이터그램 크기인 최소 1200바이트로 확장해야 MUST 한다.

이 크기의 UDP 데이터그램을 보내면 네트워크 경로가 양방향으로 합리적인 Path Maximum Transmission Unit(PMTU)을 지원함을 보장한다. 또한 Initial 패킷을 확장하는 클라이언트는 검증되지 않은 클라이언트 주소로 향하는 서버 응답으로 인한 증폭 공격의 진폭을 줄이는 데 도움이 된다. Section 8을 참조한다.

Initial 패킷을 포함하는 데이터그램은 송신자가 네트워크 경로와 피어가 자신이 선택한 크기를 모두 지원한다고 믿는 경우 1200바이트를 초과할 수 MAY 있다.

서버는 허용되는 가장 작은 최대 데이터그램 크기인 1200바이트보다 작은 페이로드를 가진 UDP 데이터그램에 운반된 Initial 패킷을 폐기해야 MUST 한다. 서버는 PROTOCOL_VIOLATION 오류 코드가 있는 CONNECTION_CLOSE 프레임을 보내 연결을 즉시 닫을 수도 MAY 있다. Section 10.2.3을 참조한다.

서버는 클라이언트의 주소를 검증하기 전 자신이 보내는 바이트 수도 제한해야 MUST 한다. Section 8을 참조한다.

14.2. Path Maximum Transmission Unit

PMTU는 IP 헤더, UDP 헤더 및 UDP 페이로드를 포함한 전체 IP 패킷의 최대 크기이다. UDP 페이로드에는 하나 이상의 QUIC 패킷 헤더와 보호된 페이로드가 포함된다. PMTU는 경로 특성에 따라 달라질 수 있으므로 시간이 지남에 따라 변경될 수 있다. 엔드포인트가 특정 시점에 보내는 가장 큰 UDP 페이로드를 엔드포인트의 최대 데이터그램 크기라고 한다.

엔드포인트는 목적지까지의 경로가 조각화 없이 원하는 최대 데이터그램 크기를 지원할지 판단하기 위해 DPLPMTUD(Section 14.3) 또는 PMTUD(Section 14.2.1)를 사용해야 SHOULD 한다. 이러한 메커니즘이 없는 경우 QUIC 엔드포인트는 허용되는 가장 작은 최대 데이터그램 크기보다 큰 데이터그램을 보내서는 SHOULD NOT 안 된다.

DPLPMTUD와 PMTUD는 모두 현재 최대 데이터그램 크기보다 큰 데이터그램을 보내며, 이를 PMTU 프로브라고 한다. PMTU 프로브로 전송되지 않는 모든 QUIC 패킷은 데이터그램이 조각화되거나 삭제되는 것을 피하기 위해 최대 데이터그램 크기 안에 맞도록 크기가 정해져야 SHOULD 한다 [RFC8085].

QUIC 엔드포인트가 로컬 및 원격 IP 주소 쌍 사이의 PMTU가 허용되는 가장 작은 최대 데이터그램 크기인 1200바이트를 지원할 수 없다고 판단하면, 해당 경로에서 PMTU 프로브 안의 패킷이나 CONNECTION_CLOSE 프레임을 포함하는 패킷을 제외하고 QUIC 패킷 전송을 즉시 중단해야 MUST 한다. 대체 경로를 찾을 수 없으면 엔드포인트는 연결을 종료할 수 MAY 있다.

로컬 주소와 원격 주소의 각 쌍은 서로 다른 PMTU를 가질 수 있다. 따라서 어떤 종류의 PMTU 발견이든 구현하는 QUIC 구현은 로컬 및 원격 IP 주소의 각 조합에 대해 최대 데이터그램 크기를 유지해야 SHOULD 한다.

QUIC 구현은 알 수 없는 터널 오버헤드나 IP 헤더 옵션/확장을 고려하기 위해 최대 데이터그램 크기를 더 보수적으로 계산할 수 MAY 있다.

14.2.1. PMTUD에 의한 ICMP 메시지 처리

PMTUD [RFC1191] [RFC8201]는 IP 패킷이 로컬 라우터 MTU보다 커서 삭제될 때 이를 나타내는 ICMP 메시지(즉, IPv6 Packet Too Big(PTB) 메시지)의 수신에 의존한다. DPLPMTUD도 선택적으로 이러한 메시지를 사용할 수 있다. 이러한 ICMP 메시지 사용은 패킷을 관찰할 수 없지만 경로에서 사용되는 주소를 성공적으로 추측할 수 있는 엔티티의 공격에 잠재적으로 취약하다. 이러한 공격은 PMTU를 대역폭 비효율적인 값으로 줄일 수 있다.

엔드포인트는 PMTU가 QUIC의 허용되는 가장 작은 최대 데이터그램 크기보다 아래로 감소했다고 주장하는 ICMP 메시지를 무시해야 MUST 한다.

ICMP 생성 요구사항 [RFC1812] [RFC4443]은 인용된 패킷이 IP 버전의 최소 MTU를 초과하지 않는 범위에서 원래 패킷을 가능한 한 많이 포함해야 한다고 명시한다. 인용된 패킷의 크기는 실제로 더 작을 수도 있고, 정보가 이해 불가능할 수도 있다. 이는 Section 1.1 of [DPLPMTUD]에 설명되어 있다.

PMTUD를 사용하는 QUIC 엔드포인트는 [RFC8201]Section 5.2 of [RFC8085]에 명시된 대로 패킷 주입으로부터 보호하기 위해 ICMP 메시지를 검증해야 SHOULD 한다. 이 검증은 ICMP 메시지의 페이로드에 제공된 인용 패킷을 사용하여 메시지를 해당 전송 연결과 연관시켜야 SHOULD 한다 (Section 4.6.1 of [DPLPMTUD] 참조). ICMP 메시지 검증에는 IP 주소와 UDP 포트의 일치 [RFC8085]가 포함되어야 MUST 하며, 가능하다면 활성 QUIC 세션에 대한 연결 ID도 포함되어야 한다. 엔드포인트는 검증에 실패한 모든 ICMP 메시지를 무시해야 SHOULD 한다.

엔드포인트는 ICMP 메시지를 기반으로 PMTU를 증가시켜서는 MUST NOT 안 된다. Section 3 of [DPLPMTUD]의 Item 6을 참조한다. ICMP 메시지에 대한 응답으로 QUIC의 최대 데이터그램 크기를 줄이는 것은 QUIC의 손실 감지 알고리즘이 인용된 패킷이 실제로 손실되었다고 판단할 때까지 잠정적일 수 MAY 있다.

14.3. Datagram Packetization Layer PMTU Discovery

DPLPMTUD [DPLPMTUD]는 PMTU 프로브에 운반되는 QUIC 패킷의 손실 또는 확인 응답 추적에 의존한다. PADDING 프레임을 사용하는 DPLPMTUD용 PMTU 프로브는 Section 4.1 of [DPLPMTUD]에 정의된 "Probing using padding data"를 구현한다.

엔드포인트는 BASE_PLPMTU(Section 5.1 of [DPLPMTUD])의 초기값을 QUIC의 허용되는 가장 작은 최대 데이터그램 크기와 일치하도록 설정해야 SHOULD 한다. MIN_PLPMTU는 BASE_PLPMTU와 같다.

DPLPMTUD를 구현하는 QUIC 엔드포인트는 로컬 및 원격 IP 주소의 각 조합에 대해 DPLPMTUD Maximum Packet Size(MPS) (Section 4.4 of [DPLPMTUD])를 유지한다. 이는 최대 데이터그램 크기에 해당한다.

14.3.1. DPLPMTUD와 초기 연결성

DPLPMTUD의 관점에서 QUIC는 확인 응답되는 Packetization Layer (PL)이다. 따라서 QUIC 송신자는 QUIC 연결 핸드셰이크가 완료되면 DPLPMTUD BASE 상태(Section 5.2 of [DPLPMTUD])에 들어갈 수 있다.

14.3.2. DPLPMTUD로 네트워크 경로 검증

QUIC는 확인 응답되는 PL이다. 따라서 QUIC 송신자는 SEARCH_COMPLETE 상태에 있는 동안 DPLPMTUD CONFIRMATION_TIMER를 구현하지 않는다. Section 5.2 of [DPLPMTUD]를 참조한다.

14.3.3. DPLPMTUD에 의한 ICMP 메시지 처리

DPLPMTUD를 사용하는 엔드포인트는 PTB 정보를 사용하기 전에 수신된 모든 ICMP PTB 메시지의 검증을 요구한다. 이는 Section 4.6 of [DPLPMTUD]에 정의되어 있다. UDP 포트 검증에 더해, QUIC는 다른 PL 정보(예: 수신한 ICMP 메시지의 인용 패킷 안의 연결 ID 검증)를 사용하여 ICMP 메시지를 검증한다.

Section 14.2.1에 설명된 ICMP 메시지 처리 고려사항은 DPLPMTUD가 이러한 메시지를 사용하는 경우에도 적용된다.

14.4. QUIC PMTU 프로브 보내기

PMTU 프로브는 ack-eliciting 패킷이다.

엔드포인트는 PMTU 프로브의 내용을 PING 및 PADDING 프레임으로 제한할 수 있다. 현재 최대 데이터그램 크기보다 큰 패킷은 네트워크에 의해 삭제될 가능성이 더 높기 때문이다. 따라서 PMTU 프로브에 운반되는 QUIC 패킷의 손실은 혼잡의 신뢰할 수 있는 지표가 아니며 혼잡 제어 반응을 트리거해서는 SHOULD NOT 안 된다. Section 3 of [DPLPMTUD]의 Item 7을 참조한다. 그러나 PMTU 프로브는 혼잡 윈도우를 소비하며, 이는 애플리케이션의 후속 전송을 지연시킬 수 있다.

14.4.1. Source Connection ID를 포함하는 PMTU 프로브

들어오는 QUIC 패킷을 라우팅하기 위해 Destination Connection ID 필드에 의존하는 엔드포인트는, 그 결과로 발생하는 ICMP 메시지 (Section 14.2.1)를 올바른 엔드포인트로 다시 라우팅하기 위해 PMTU 프로브에 연결 ID가 포함될 것을 요구할 가능성이 높다. 그러나 Source Connection ID 필드는 긴 헤더 패킷(Section 17.2)에만 포함되며, 긴 헤더 패킷은 핸드셰이크가 완료된 후 피어에 의해 복호화되거나 확인 응답되지 않는다.

PMTU 프로브를 구성하는 한 가지 방법은 Handshake 또는 0-RTT 패킷(Section 17.2)과 같은 긴 헤더가 있는 패킷을 짧은 헤더 패킷과 단일 UDP 데이터그램으로 병합하는 것이다 (Section 12.2 참조). 결과 PMTU 프로브가 엔드포인트에 도달하면, 긴 헤더가 있는 패킷은 무시되지만 짧은 헤더 패킷은 확인 응답된다. PMTU 프로브가 ICMP 메시지를 보내게 하면, 프로브의 첫 부분이 그 메시지에 인용된다. Source Connection ID 필드가 프로브의 인용된 부분 안에 있다면, 이는 ICMP 메시지의 라우팅 또는 검증에 사용될 수 있다.

15. 버전

QUIC 버전은 32비트 부호 없는 숫자를 사용하여 식별된다.

버전 0x00000000은 버전 협상을 나타내기 위해 예약되어 있다. 이 명세의 버전은 숫자 0x00000001로 식별된다.

QUIC의 다른 버전은 이 버전과 다른 속성을 가질 수 있다. 프로토콜의 모든 버전에서 일관되도록 보장되는 QUIC의 속성은 [QUIC-INVARIANTS]에 설명되어 있다.

QUIC 버전 0x00000001은 [QUIC-TLS]에 설명된 대로 TLS를 암호화 핸드셰이크 프로토콜로 사용한다.

버전 번호의 최상위 16비트가 0인 버전은 향후 IETF 합의 문서에서 사용하기 위해 예약되어 있다.

패턴 0x?a?a?a?a를 따르는 버전은 버전 협상이 실행되도록 강제하는 데 사용하기 위해 예약되어 있다. 즉, 모든 바이트의 하위 4비트가 1010(이진수)인 모든 버전 번호가 이에 해당한다. 클라이언트나 서버는 이러한 예약된 버전 중 어느 것에 대한 지원도 광고할 수 MAY 있다.

예약된 버전 번호는 실제 프로토콜을 나타내지 않는다. 클라이언트는 서버가 버전 협상을 시작할 것이라는 기대 하에 이러한 버전 번호 중 하나를 사용할 수 MAY 있다. 서버는 이러한 버전 중 하나에 대한 지원을 광고할 수 MAY 있으며, 클라이언트가 그 값을 무시할 것으로 기대할 수 있다.

16. 가변 길이 정수 인코딩

QUIC 패킷과 프레임은 음이 아닌 정수 값에 대해 일반적으로 가변 길이 인코딩을 사용한다. 이 인코딩은 더 작은 정수 값을 인코딩하는 데 더 적은 바이트가 필요하도록 보장한다.

QUIC 가변 길이 정수 인코딩은 첫 바이트의 최상위 두 비트를 예약하여 정수 인코딩 길이의 2진 로그를 바이트 단위로 인코딩한다. 정수 값은 남은 비트에 네트워크 바이트 순서로 인코딩된다.

이는 정수가 1, 2, 4 또는 8바이트로 인코딩되고 각각 6비트, 14비트, 30비트 또는 62비트 값을 인코딩할 수 있음을 의미한다. Table 4는 인코딩 속성을 요약한다.

Table 4: 정수 인코딩 요약
2MSB 길이 사용 가능한 비트 범위
00 1 6 0-63
01 2 14 0-16383
10 4 30 0-1073741823
11 8 62 0-4611686018427387903

디코딩 알고리즘의 예와 샘플 인코딩은 Appendix A.1에 표시되어 있다.

Frame Type 필드라는 유일한 예외를 제외하면, 값은 필요한 최소 바이트 수로 인코딩될 필요가 없다. Section 12.4를 참조한다.

버전(Section 15), 헤더에 전송되는 패킷 번호 (Section 17.1), 그리고 긴 헤더 패킷의 연결 ID 길이 (Section 17.2)는 정수를 사용하여 설명되지만 이 인코딩은 사용하지 않는다.

17. 패킷 형식

모든 숫자 값은 네트워크 바이트 순서(즉, 빅 엔디언)로 인코딩되며, 모든 필드 크기는 비트 단위이다. 필드 값을 설명할 때는 16진수 표기법이 사용된다.

17.1. 패킷 번호 인코딩 및 디코딩

패킷 번호는 0부터 262-1 범위의 정수이다 (Section 12.3). 긴 패킷 헤더나 짧은 패킷 헤더에 존재할 때, 패킷 번호는 1~4바이트로 인코딩된다. 패킷 번호를 나타내는 데 필요한 비트 수는 패킷 번호의 최하위 비트만 포함함으로써 줄어든다.

인코딩된 패킷 번호는 Section 5.4 of [QUIC-TLS]에 설명된 대로 보호된다.

패킷 번호 공간에 대한 확인 응답을 수신하기 전에는, 아래에 설명된 것처럼 잘라내지 말고 전체 패킷 번호가 포함되어야 MUST 한다.

패킷 번호 공간에 대한 확인 응답을 수신한 후, 송신자는 가장 큰 확인 응답된 패킷 번호와 전송 중인 패킷 번호 사이의 차이보다 두 배 넘게 큰 범위를 나타낼 수 있는 패킷 번호 크기를 사용해야 MUST 한다. 그러면 패킷을 수신하는 피어는, 더 높은 번호의 많은 패킷을 수신한 후에야 패킷이 도착할 정도로 전송 중 지연되지 않는 한, 패킷 번호를 올바르게 디코딩한다. 엔드포인트는 이후 전송된 패킷들 뒤에 패킷이 도착하더라도 패킷 번호가 복구될 수 있도록 충분히 큰 패킷 번호 인코딩을 사용해야 SHOULD 한다.

그 결과, 패킷 번호 인코딩의 크기는 새 패킷을 포함하여 연속된 확인 응답되지 않은 패킷 번호 수의 2진 로그보다 최소 1비트 더 크다. 패킷 번호 인코딩에 대한 의사코드와 예는 Appendix A.2에서 찾을 수 있다.

수신자에서는 전체 패킷 번호를 복구하기 전에 패킷 번호의 보호가 제거된다. 그런 다음 전체 패킷 번호는 존재하는 유효 비트 수, 그 비트들의 값, 그리고 성공적으로 인증된 패킷에서 수신된 가장 큰 패킷 번호를 기준으로 재구성된다. 전체 패킷 번호를 복구하는 것은 패킷 보호 제거를 성공적으로 완료하는 데 필요하다.

헤더 보호가 제거되면, 패킷 번호는 다음으로 기대되는 패킷에 가장 가까운 패킷 번호 값을 찾아 디코딩된다. 다음으로 기대되는 패킷은 수신된 가장 높은 패킷 번호에 1을 더한 것이다. 패킷 번호 디코딩에 대한 의사코드와 예는 Appendix A.3에서 찾을 수 있다.

17.2. 긴 헤더 패킷

Long Header Packet {
  Header Form (1) = 1,
  Fixed Bit (1) = 1,
  Long Packet Type (2),
  Type-Specific Bits (4),
  Version (32),
  Destination Connection ID Length (8),
  Destination Connection ID (0..160),
  Source Connection ID Length (8),
  Source Connection ID (0..160),
  Type-Specific Payload (..),
}
Figure 13: 긴 헤더 패킷 형식

긴 헤더는 1-RTT 키가 설정되기 전에 전송되는 패킷에 사용된다. 1-RTT 키를 사용할 수 있게 되면 송신자는 짧은 헤더를 사용하여 패킷을 보내도록 전환한다(Section 17.3). 긴 형식은 Version Negotiation 패킷과 같은 특수 패킷이 이 균일한 고정 길이 패킷 형식으로 표현될 수 있게 한다. 긴 헤더를 사용하는 패킷은 다음 필드를 포함한다:

Header Form:

byte 0(첫 번째 바이트)의 최상위 비트(0x80)는 긴 헤더의 경우 1로 설정된다.

Fixed Bit:

byte 0의 다음 비트(0x40)는 패킷이 Version Negotiation 패킷이 아닌 한 1로 설정된다. 이 비트에 0 값을 포함하는 패킷은 이 버전에서 유효한 패킷이 아니며 폐기되어야 MUST 한다. 이 비트의 값이 1이면 QUIC가 다른 프로토콜과 공존할 수 있다. [RFC7983]을 참조한다.

Long Packet Type:

byte 0의 다음 두 비트(마스크 0x30을 가진 비트)는 패킷 유형을 포함한다. 패킷 유형은 Table 5에 나열되어 있다.

Type-Specific Bits:

byte 0의 하위 네 비트(마스크 0x0f를 가진 비트)의 의미론은 패킷 유형에 의해 결정된다.

Version:

QUIC Version은 첫 번째 바이트 뒤에 오는 32비트 필드이다. 이 필드는 사용 중인 QUIC 버전을 나타내며, 나머지 프로토콜 필드가 어떻게 해석되는지 결정한다.

Destination Connection ID Length:

버전 뒤의 바이트는 그 뒤에 오는 Destination Connection ID 필드의 길이를 바이트 단위로 포함한다. 이 길이는 8비트 부호 없는 정수로 인코딩된다. QUIC 버전 1에서 이 값은 20바이트를 초과해서는 MUST NOT 안 된다. 20보다 큰 값을 가진 버전 1 긴 헤더를 수신하는 엔드포인트는 패킷을 삭제해야 MUST 한다. Version Negotiation 패킷을 올바르게 형성하기 위해, 서버는 다른 QUIC 버전의 더 긴 연결 ID를 읽을 수 있어야 SHOULD 한다.

Destination Connection ID:

Destination Connection ID 필드는 이 필드의 길이를 나타내는 Destination Connection ID Length 필드 뒤에 온다. Section 7.2는 이 필드의 사용을 더 자세히 설명한다.

Source Connection ID Length:

Destination Connection ID 뒤의 바이트는 그 뒤에 오는 Source Connection ID 필드의 길이를 바이트 단위로 포함한다. 이 길이는 8비트 부호 없는 정수로 인코딩된다. QUIC 버전 1에서 이 값은 20바이트를 초과해서는 MUST NOT 안 된다. 20보다 큰 값을 가진 버전 1 긴 헤더를 수신하는 엔드포인트는 패킷을 삭제해야 MUST 한다. Version Negotiation 패킷을 올바르게 형성하기 위해, 서버는 다른 QUIC 버전의 더 긴 연결 ID를 읽을 수 있어야 SHOULD 한다.

Source Connection ID:

Source Connection ID 필드는 이 필드의 길이를 나타내는 Source Connection ID Length 필드 뒤에 온다. Section 7.2는 이 필드의 사용을 더 자세히 설명한다.

Type-Specific Payload:

패킷의 나머지 부분이 있다면 유형별로 다르다.

이 QUIC 버전에서는 긴 헤더를 가진 다음 패킷 유형이 정의된다:

Table 5: 긴 헤더 패킷 유형
유형 이름 섹션
0x00 Initial Section 17.2.2
0x01 0-RTT Section 17.2.3
0x02 Handshake Section 17.2.4
0x03 Retry Section 17.2.5

긴 헤더 패킷의 header form 비트, Destination 및 Source Connection ID 길이, Destination 및 Source Connection ID 필드, 그리고 Version 필드는 버전 독립적이다. 첫 번째 바이트의 다른 필드는 버전별로 다르다. 서로 다른 QUIC 버전의 패킷이 어떻게 해석되는지에 대한 자세한 내용은 [QUIC-INVARIANTS]를 참조한다.

필드와 페이로드의 해석은 버전 및 패킷 유형에 특정된다. 이 버전의 유형별 의미론은 다음 섹션들에서 설명되지만, 이 QUIC 버전의 여러 긴 헤더 패킷은 다음 추가 필드를 포함한다:

Reserved Bits:

byte 0의 두 비트(마스크 0x0c를 가진 비트)는 여러 패킷 유형에 걸쳐 예약되어 있다. 이 비트들은 헤더 보호를 사용하여 보호된다. Section 5.4 of [QUIC-TLS]를 참조한다. 보호 전에 포함되는 값은 0으로 설정되어야 MUST 한다. 엔드포인트는 패킷 보호와 헤더 보호를 모두 제거한 후 이 비트들에 0이 아닌 값을 가진 패킷을 수신하면 이를 PROTOCOL_VIOLATION 유형의 연결 오류로 처리해야 MUST 한다. 헤더 보호만 제거한 후 그러한 패킷을 폐기하면 엔드포인트가 공격에 노출될 수 있다. Section 9.5 of [QUIC-TLS]를 참조한다.

Packet Number Length:

Packet Number 필드를 포함하는 패킷 유형에서 byte 0의 최하위 두 비트(마스크 0x03을 가진 비트)는 Packet Number 필드의 길이를 포함한다. 이는 바이트 단위의 Packet Number 필드 길이보다 하나 작은 부호 없는 2비트 정수로 인코딩된다. 즉 Packet Number 필드의 길이는 이 필드의 값에 1을 더한 값이다. 이 비트들은 헤더 보호를 사용하여 보호된다. Section 5.4 of [QUIC-TLS]를 참조한다.

Length:

이는 패킷의 나머지 부분(즉 Packet Number 및 Payload 필드)의 길이를 바이트 단위로 나타내며, 가변 길이 정수 (Section 16)로 인코딩된다.

Packet Number:

이 필드는 1~4바이트 길이이다. 패킷 번호는 헤더 보호를 사용하여 보호된다. Section 5.4 of [QUIC-TLS]를 참조한다. Packet Number 필드의 길이는 byte 0의 Packet Number Length 비트에 인코딩된다. 위를 참조한다.

Packet Payload:

이는 프레임의 시퀀스를 포함하는 패킷의 페이로드이며, 패킷 보호를 사용하여 보호된다.

17.2.1. Version Negotiation 패킷

Version Negotiation 패킷은 본질적으로 버전에 특정되지 않는다. 클라이언트가 이를 수신하면, Version 필드의 값이 0인 것을 기준으로 Version Negotiation 패킷으로 식별된다.

Version Negotiation 패킷은 서버가 지원하지 않는 버전을 포함하는 클라이언트 패킷에 대한 응답이다. 이는 서버에 의해서만 전송된다.

Version Negotiation 패킷의 레이아웃은 다음과 같다:

Version Negotiation Packet {
  Header Form (1) = 1,
  Unused (7),
  Version (32) = 0,
  Destination Connection ID Length (8),
  Destination Connection ID (0..2040),
  Source Connection ID Length (8),
  Source Connection ID (0..2040),
  Supported Version (32) ...,
}
Figure 14: Version Negotiation 패킷

Unused 필드의 값은 서버가 임의의 값으로 설정한다. 클라이언트는 이 필드의 값을 무시해야 MUST 한다. QUIC가 다른 프로토콜과 다중화될 수 있는 경우([RFC7983] 참조), 서버는 Version Negotiation 패킷에 Fixed Bit 필드가 있는 것처럼 보이도록 이 필드의 최상위 비트(0x40)를 1로 설정해야 SHOULD 한다. 다른 QUIC 버전은 유사한 권고를 하지 않을 수 있음에 유의한다.

Version Negotiation 패킷의 Version 필드는 0x00000000으로 설정되어야 MUST 한다.

서버는 자신이 수신한 패킷의 Source Connection ID 필드 값을 Destination Connection ID 필드에 포함해야 MUST 한다. Source Connection ID의 값은 수신한 패킷의 Destination Connection ID에서 복사되어야 MUST 하며, 이는 처음에 클라이언트가 무작위로 선택한 값이다. 두 연결 ID를 모두 에코하면 클라이언트는 서버가 패킷을 수신했으며 Version Negotiation 패킷이 Initial 패킷을 관찰하지 않은 엔티티에 의해 생성되지 않았다는 어느 정도의 확신을 얻는다.

향후 QUIC 버전은 연결 ID 길이에 대해 다른 요구사항을 가질 수 있다. 특히 연결 ID는 더 작은 최소 길이나 더 큰 최대 길이를 가질 수 있다. 따라서 연결 ID에 대한 버전별 규칙은 Version Negotiation 패킷을 보낼지 여부에 대한 결정에 영향을 주어서는 MUST NOT 안 된다.

Version Negotiation 패킷의 나머지 부분은 서버가 지원하는 32비트 버전의 목록이다.

Version Negotiation 패킷은 확인 응답되지 않는다. 이는 지원되지 않는 버전을 나타내는 패킷에 대한 응답으로만 전송된다. Section 5.2.2를 참조한다.

Version Negotiation 패킷은 긴 헤더 형식을 사용하는 다른 패킷에 존재하는 Packet Number 및 Length 필드를 포함하지 않는다. 따라서 Version Negotiation 패킷은 전체 UDP 데이터그램을 소비한다.

서버는 단일 UDP 데이터그램에 대한 응답으로 둘 이상의 Version Negotiation 패킷을 보내서는 MUST NOT 안 된다.

버전 협상 절차에 대한 설명은 Section 6을 참조한다.

17.2.2. Initial 패킷

Initial 패킷은 type 값 0x00의 긴 헤더를 사용한다. 이는 키 교환을 수행하기 위해 클라이언트와 서버가 보내는 첫 CRYPTO 프레임을 운반하며, 양방향으로 ACK 프레임을 운반한다.

Initial Packet {
  Header Form (1) = 1,
  Fixed Bit (1) = 1,
  Long Packet Type (2) = 0,
  Reserved Bits (2),
  Packet Number Length (2),
  Version (32),
  Destination Connection ID Length (8),
  Destination Connection ID (0..160),
  Source Connection ID Length (8),
  Source Connection ID (0..160),
  Token Length (i),
  Token (..),
  Length (i),
  Packet Number (8..32),
  Packet Payload (8..),
}
Figure 15: Initial 패킷

Initial 패킷은 긴 헤더뿐 아니라 Length 및 Packet Number 필드를 포함한다. Section 17.2를 참조한다. 첫 번째 바이트는 Reserved 및 Packet Number Length 비트를 포함한다. Section 17.2도 참조한다. Source Connection ID와 Length 필드 사이에는 Initial 패킷에 특정된 두 개의 추가 필드가 있다.

Token Length:

Token 필드의 길이를 바이트 단위로 지정하는 가변 길이 정수이다. 토큰이 없으면 이 값은 0이다. 서버가 보내는 Initial 패킷은 Token Length 필드를 0으로 설정해야 MUST 한다. 0이 아닌 Token Length 필드를 가진 Initial 패킷을 수신한 클라이언트는 패킷을 폐기하거나 PROTOCOL_VIOLATION 유형의 연결 오류를 생성해야 MUST 한다.

Token:

이전에 Retry 패킷 또는 NEW_TOKEN 프레임에서 제공된 토큰의 값이다. Section 8.1을 참조한다.

버전을 인식하지 못하는 미들박스에 의한 변조를 방지하기 위해, Initial 패킷은 [QUIC-TLS]에 설명된 대로 연결 및 버전에 특정된 키(Initial 키)로 보호된다. 이 보호는 패킷을 관찰할 수 있는 공격자에 대한 기밀성이나 무결성을 제공하지 않지만, 패킷을 관찰할 수 없는 공격자가 Initial 패킷을 스푸핑하는 것은 방지한다.

클라이언트와 서버는 초기 암호화 핸드셰이크 메시지를 포함하는 모든 패킷에 Initial 패킷 유형을 사용한다. 여기에는 Retry 패킷을 수신한 후 보내는 패킷처럼, 초기 암호화 메시지를 포함하는 새 패킷을 생성해야 하는 모든 경우가 포함된다. Section 17.2.5를 참조한다.

서버는 클라이언트 Initial에 대한 응답으로 자신의 첫 Initial 패킷을 보낸다. 서버는 여러 Initial 패킷을 보낼 수 MAY 있다. 암호화 키 교환은 이 데이터의 여러 왕복이나 재전송을 요구할 수 있다.

Initial 패킷의 페이로드는 암호화 핸드셰이크 메시지를 포함하는 CRYPTO 프레임(또는 프레임들), ACK 프레임, 또는 둘 다를 포함한다. PING, PADDING 및 type 0x1c의 CONNECTION_CLOSE 프레임도 허용된다. 다른 프레임을 포함하는 Initial 패킷을 수신한 엔드포인트는 그 패킷을 불필요한 것으로 폐기하거나 연결 오류로 처리할 수 있다.

클라이언트가 보내는 첫 패킷은 항상 첫 암호화 핸드셰이크 메시지의 시작 부분 또는 전체를 포함하는 CRYPTO 프레임을 포함한다. 처음 전송되는 CRYPTO 프레임은 항상 오프셋 0에서 시작한다. Section 7을 참조한다.

서버가 TLS HelloRetryRequest를 보내면 (Section 4.7 of [QUIC-TLS] 참조), 클라이언트는 또 다른 Initial 패킷 시리즈를 보낸다는 점에 유의한다. 이러한 Initial 패킷은 암호화 핸드셰이크를 계속하며, 첫 번째 Initial 패킷 플라이트에서 보낸 CRYPTO 프레임의 크기와 일치하는 오프셋에서 시작하는 CRYPTO 프레임을 포함한다.

17.2.2.1. Initial 패킷 포기

클라이언트는 자신의 첫 Handshake 패킷을 보내면 Initial 패킷의 송신과 처리를 모두 중단한다. 서버는 자신의 첫 Handshake 패킷을 수신하면 Initial 패킷의 송신과 처리를 중단한다. 패킷이 아직 비행 중이거나 확인 응답을 기다리고 있을 수 있지만, 이 시점 이후에는 더 이상의 Initial 패킷을 교환할 필요가 없다. Initial 패킷 보호 키는 폐기되며 (Section 4.9.1 of [QUIC-TLS] 참조), 모든 손실 복구 및 혼잡 제어 상태도 함께 폐기된다. Section 6.4 of [QUIC-RECOVERY]를 참조한다.

Initial 키가 폐기되면 CRYPTO 프레임 안의 모든 데이터는 폐기되며 더 이상 재전송되지 않는다.

17.2.3. 0-RTT

0-RTT 패킷은 type 값 0x01의 긴 헤더를 사용하며, 그 뒤에 Length 및 Packet Number 필드가 온다. Section 17.2를 참조한다. 첫 번째 바이트는 Reserved 및 Packet Number Length 비트를 포함한다. Section 17.2를 참조한다. 0-RTT 패킷은 핸드셰이크 완료 전에 첫 번째 플라이트의 일부로 클라이언트에서 서버로 "early" 데이터를 운반하는 데 사용된다. TLS 핸드셰이크의 일부로 서버는 이 early 데이터를 수락하거나 거부할 수 있다.

0-RTT 데이터와 그 제한사항에 대한 논의는 Section 2.3 of [TLS13]을 참조한다.

0-RTT Packet {
  Header Form (1) = 1,
  Fixed Bit (1) = 1,
  Long Packet Type (2) = 1,
  Reserved Bits (2),
  Packet Number Length (2),
  Version (32),
  Destination Connection ID Length (8),
  Destination Connection ID (0..160),
  Source Connection ID Length (8),
  Source Connection ID (0..160),
  Length (i),
  Packet Number (8..32),
  Packet Payload (8..),
}
Figure 16: 0-RTT 패킷

0-RTT로 보호된 패킷의 패킷 번호는 1-RTT로 보호된 패킷과 같은 공간을 사용한다.

클라이언트가 Retry 패킷을 수신한 후에는 0-RTT 패킷이 손실되었거나 서버에 의해 폐기되었을 가능성이 높다. 클라이언트는 새 Initial 패킷을 보낸 후 0-RTT 패킷의 데이터를 다시 보내려고 시도해야 SHOULD 한다. 전송되는 모든 새 패킷에는 새 패킷 번호를 사용해야 MUST 한다. Section 17.2.5.3에 설명된 것처럼, 패킷 번호를 재사용하면 패킷 보호가 손상될 수 있다.

클라이언트는 핸드셰이크가 완료된 후에만 자신의 0-RTT 패킷에 대한 확인 응답을 수신한다. 이는 Section 4.1.1 of [QUIC-TLS]에 정의되어 있다.

클라이언트는 서버로부터 1-RTT 패킷을 처리하기 시작하면 0-RTT 패킷을 보내서는 MUST NOT 안 된다. 이는 0-RTT 패킷이 1-RTT 패킷의 프레임에 대한 어떤 응답도 포함할 수 없음을 의미한다. 예를 들어 클라이언트는 0-RTT 패킷으로 ACK 프레임을 보낼 수 없다. 이는 1-RTT 패킷만 확인 응답할 수 있기 때문이다. 1-RTT 패킷에 대한 확인 응답은 1-RTT 패킷에 운반되어야 MUST 한다.

서버는 기억된 한도(Section 7.4.1)의 위반을 적절한 유형의 연결 오류로 처리해야 SHOULD 한다 (예를 들어 스트림 데이터 한도를 초과한 경우 FLOW_CONTROL_ERROR).

17.2.4. Handshake 패킷

Handshake 패킷은 type 값 0x02의 긴 헤더를 사용하며, 그 뒤에 Length 및 Packet Number 필드가 온다. Section 17.2를 참조한다. 첫 번째 바이트는 Reserved 및 Packet Number Length 비트를 포함한다. Section 17.2를 참조한다. 이는 서버와 클라이언트의 암호화 핸드셰이크 메시지와 확인 응답을 운반하는 데 사용된다.

Handshake Packet {
  Header Form (1) = 1,
  Fixed Bit (1) = 1,
  Long Packet Type (2) = 2,
  Reserved Bits (2),
  Packet Number Length (2),
  Version (32),
  Destination Connection ID Length (8),
  Destination Connection ID (0..160),
  Source Connection ID Length (8),
  Source Connection ID (0..160),
  Length (i),
  Packet Number (8..32),
  Packet Payload (8..),
}
Figure 17: Handshake로 보호된 패킷

클라이언트가 서버로부터 Handshake 패킷을 수신하면, 클라이언트는 이후의 암호화 핸드셰이크 메시지와 확인 응답을 서버에 보내기 위해 Handshake 패킷을 사용한다.

Handshake 패킷의 Destination Connection ID 필드는 패킷의 수신자가 선택한 연결 ID를 포함한다. Source Connection ID는 패킷의 송신자가 사용하고자 하는 연결 ID를 포함한다. Section 7.2를 참조한다.

Handshake 패킷은 자체 패킷 번호 공간을 가지므로, 서버가 보내는 첫 Handshake 패킷은 패킷 번호 0을 포함한다.

이 패킷의 페이로드는 CRYPTO 프레임을 포함하며 PING, PADDING 또는 ACK 프레임을 포함할 수 있다. Handshake 패킷은 type 0x1c의 CONNECTION_CLOSE 프레임을 포함할 수 MAY 있다. 엔드포인트는 다른 프레임을 가진 Handshake 패킷 수신을 PROTOCOL_VIOLATION 유형의 연결 오류로 처리해야 MUST 한다.

Initial 패킷(Section 17.2.2.1 참조)과 마찬가지로, Handshake 패킷용 CRYPTO 프레임의 데이터는 Handshake 보호 키가 폐기될 때 폐기되며 더 이상 재전송되지 않는다.

17.2.5. Retry 패킷

Figure 18에 표시된 것처럼, Retry 패킷은 type 값 0x03의 긴 패킷 헤더를 사용한다. 이는 서버가 생성한 주소 검증 토큰을 운반한다. Retry를 수행하려는 서버가 이를 사용한다. Section 8.1을 참조한다.

Retry Packet {
  Header Form (1) = 1,
  Fixed Bit (1) = 1,
  Long Packet Type (2) = 3,
  Unused (4),
  Version (32),
  Destination Connection ID Length (8),
  Destination Connection ID (0..160),
  Source Connection ID Length (8),
  Source Connection ID (0..160),
  Retry Token (..),
  Retry Integrity Tag (128),
}
Figure 18: Retry 패킷

Retry 패킷은 보호된 필드를 포함하지 않는다. Unused 필드의 값은 서버가 임의의 값으로 설정하며, 클라이언트는 이 비트들을 무시해야 MUST 한다. 긴 헤더의 필드 외에도 다음 추가 필드를 포함한다:

Retry Token:

서버가 클라이언트의 주소를 검증하는 데 사용할 수 있는 불투명 토큰이다.

Retry Integrity Tag:

[QUIC-TLS]의 Section 5.8 ("Retry Packet Integrity")에 정의되어 있다.

17.2.5.1. Retry 패킷 보내기

서버는 클라이언트가 Initial 패킷의 Source Connection ID에 포함한 연결 ID로 Destination Connection ID를 채운다.

서버는 자신이 선택한 연결 ID를 Source Connection ID 필드에 포함한다. 이 값은 클라이언트가 보낸 패킷의 Destination Connection ID 필드와 같아서는 MUST NOT 안 된다. 클라이언트는 자신의 Initial 패킷의 Destination Connection ID 필드와 동일한 Source Connection ID 필드를 포함하는 Retry 패킷을 폐기해야 MUST 한다. 클라이언트는 Retry 패킷의 Source Connection ID 필드 값을 이후 자신이 보내는 패킷의 Destination Connection ID 필드에 사용해야 MUST 한다.

서버는 Initial 및 0-RTT 패킷에 대한 응답으로 Retry 패킷을 보낼 수 MAY 있다. 서버는 수신한 0-RTT 패킷을 폐기하거나 버퍼링할 수 있다. 서버는 Initial 또는 0-RTT 패킷을 수신함에 따라 여러 Retry 패킷을 보낼 수 있다. 서버는 단일 UDP 데이터그램에 대한 응답으로 둘 이상의 Retry 패킷을 보내서는 MUST NOT 안 된다.

17.2.5.2. Retry 패킷 처리

클라이언트는 각 연결 시도에 대해 최대 하나의 Retry 패킷만 수락하고 처리해야 MUST 한다. 클라이언트가 서버로부터 Initial 또는 Retry 패킷을 수신하고 처리한 후에는, 이후 수신하는 모든 Retry 패킷을 폐기해야 MUST 한다.

클라이언트는 검증할 수 없는 Retry Integrity Tag를 가진 Retry 패킷을 폐기해야 MUST 한다. Section 5.8 of [QUIC-TLS]를 참조한다. 이는 공격자가 Retry 패킷을 주입하는 능력을 줄이고 Retry 패킷의 우발적 손상으로부터 보호한다. 클라이언트는 길이가 0인 Retry Token 필드를 가진 Retry 패킷을 폐기해야 MUST 한다.

클라이언트는 연결 설정을 계속하기 위해 제공된 Retry 토큰을 포함하는 Initial 패킷으로 Retry 패킷에 응답한다.

클라이언트는 이 Initial 패킷의 Destination Connection ID 필드를 Retry 패킷의 Source Connection ID 필드 값으로 설정한다. Destination Connection ID 필드를 변경하면 Initial 패킷을 보호하는 데 사용되는 키도 변경된다. 또한 Token 필드를 Retry 패킷에 제공된 토큰으로 설정한다. 서버가 자신의 토큰 검증 로직의 일부로 연결 ID를 포함할 수 있으므로, 클라이언트는 Source Connection ID를 변경해서는 MUST NOT 안 된다. Section 8.1.4를 참조한다.

Retry 패킷은 패킷 번호를 포함하지 않으며, 클라이언트가 명시적으로 확인 응답할 수 없다.

17.2.5.3. Retry 이후 핸드셰이크 계속하기

클라이언트의 후속 Initial 패킷은 Retry 패킷의 연결 ID와 토큰 값을 포함한다. 클라이언트는 Retry 패킷의 Source Connection ID 필드를 Destination Connection ID 필드로 복사하고, 업데이트된 값을 가진 Initial 패킷이 수신될 때까지 이 값을 사용한다. Section 7.2를 참조한다. Token 필드의 값은 모든 후속 Initial 패킷에 복사된다. Section 8.1.2를 참조한다.

Destination Connection ID 및 Token 필드를 업데이트하는 것 외에는, 클라이언트가 보내는 Initial 패킷은 첫 Initial 패킷과 동일한 제한을 받는다. 클라이언트는 이 패킷에 포함했던 것과 같은 암호화 핸드셰이크 메시지를 사용해야 MUST 한다. 서버는 다른 암호화 핸드셰이크 메시지를 포함하는 패킷을 연결 오류로 처리하거나 폐기할 수 MAY 있다. Token 필드를 포함하면 암호화 핸드셰이크 메시지에 사용할 수 있는 공간이 줄어들어 클라이언트가 여러 Initial 패킷을 보내야 할 수 있음에 유의한다.

클라이언트는 Retry 패킷을 수신한 후 서버가 제공한 연결 ID로 0-RTT 패킷을 보내 0-RTT를 시도할 수 MAY 있다.

클라이언트는 Retry 패킷을 처리한 후 어떤 패킷 번호 공간에 대해서도 패킷 번호를 재설정해서는 MUST NOT 안 된다. 특히 0-RTT 패킷은 Retry 패킷 수신 시 재전송될 가능성이 매우 높은 기밀 정보를 포함한다. 이러한 새 0-RTT 패킷을 보호하는 데 사용되는 키는 Retry 패킷에 응답한 결과로 변경되지 않는다. 그러나 이 패킷들에 전송되는 데이터는 이전에 전송된 것과 다를 수 있다. 같은 패킷 번호로 이러한 새 패킷을 보내면 같은 키와 nonce가 서로 다른 내용을 보호하는 데 사용될 수 있으므로, 해당 패킷의 패킷 보호가 손상될 가능성이 높다. 서버는 클라이언트가 패킷 번호를 재설정한 것을 감지하면 연결을 중단할 수 MAY 있다.

클라이언트와 서버 사이에서 교환되는 Initial 및 Retry 패킷에 사용된 연결 ID는 전송 매개변수로 복사되어 Section 7.3에 설명된 대로 검증된다.

17.3. 짧은 헤더 패킷

이 QUIC 버전은 짧은 패킷 헤더를 사용하는 단일 패킷 유형을 정의한다.

17.3.1. 1-RTT 패킷

1-RTT 패킷은 짧은 패킷 헤더를 사용한다. 이는 버전과 1-RTT 키가 협상된 후 사용된다.

1-RTT Packet {
  Header Form (1) = 0,
  Fixed Bit (1) = 1,
  Spin Bit (1),
  Reserved Bits (2),
  Key Phase (1),
  Packet Number Length (2),
  Destination Connection ID (0..160),
  Packet Number (8..32),
  Packet Payload (8..),
}
Figure 19: 1-RTT 패킷

1-RTT 패킷은 다음 필드를 포함한다:

Header Form:

byte 0의 최상위 비트(0x80)는 짧은 헤더의 경우 0으로 설정된다.

Fixed Bit:

byte 0의 다음 비트(0x40)는 1로 설정된다. 이 비트에 0 값을 포함하는 패킷은 이 버전에서 유효한 패킷이 아니며 폐기되어야 MUST 한다. 이 비트의 값이 1이면 QUIC가 다른 프로토콜과 공존할 수 있다. [RFC7983]을 참조한다.

Spin Bit:

byte 0의 세 번째 최상위 비트(0x20)는 지연 시간 spin bit이며, Section 17.4에 설명된 대로 설정된다.

Reserved Bits:

byte 0의 다음 두 비트(마스크 0x18을 가진 비트)는 예약되어 있다. 이 비트들은 헤더 보호를 사용하여 보호된다. Section 5.4 of [QUIC-TLS]를 참조한다. 보호 전에 포함되는 값은 0으로 설정되어야 MUST 한다. 엔드포인트는 패킷 보호와 헤더 보호를 모두 제거한 후 이 비트들에 0이 아닌 값을 가진 패킷을 수신하면 이를 PROTOCOL_VIOLATION 유형의 연결 오류로 처리해야 MUST 한다. 헤더 보호만 제거한 후 그러한 패킷을 폐기하면 엔드포인트가 공격에 노출될 수 있다. Section 9.5 of [QUIC-TLS]를 참조한다.

Key Phase:

byte 0의 다음 비트(0x04)는 키 단계를 나타내며, 패킷의 수신자가 그 패킷을 보호하는 데 사용된 패킷 보호 키를 식별할 수 있게 한다. 자세한 내용은 [QUIC-TLS]를 참조한다. 이 비트는 헤더 보호를 사용하여 보호된다. Section 5.4 of [QUIC-TLS]를 참조한다.

Packet Number Length:

byte 0의 최하위 두 비트(마스크 0x03을 가진 비트)는 Packet Number 필드의 길이를 포함한다. 이는 바이트 단위의 Packet Number 필드 길이보다 하나 작은 부호 없는 2비트 정수로 인코딩된다. 즉 Packet Number 필드의 길이는 이 필드의 값에 1을 더한 값이다. 이 비트들은 헤더 보호를 사용하여 보호된다. Section 5.4 of [QUIC-TLS]를 참조한다.

Destination Connection ID:

Destination Connection ID는 패킷의 의도된 수신자가 선택한 연결 ID이다. 자세한 내용은 Section 5.1을 참조한다.

Packet Number:

Packet Number 필드는 1~4바이트 길이이다. 패킷 번호는 헤더 보호를 사용하여 보호된다. Section 5.4 of [QUIC-TLS]를 참조한다. Packet Number 필드의 길이는 Packet Number Length 필드에 인코딩된다. 자세한 내용은 Section 17.1을 참조한다.

Packet Payload:

1-RTT 패킷은 항상 1-RTT로 보호된 페이로드를 포함한다.

짧은 헤더 패킷의 header form 비트와 Destination Connection ID 필드는 버전 독립적이다. 나머지 필드는 선택된 QUIC 버전에 특정된다. 서로 다른 QUIC 버전의 패킷이 어떻게 해석되는지에 대한 자세한 내용은 [QUIC-INVARIANTS]를 참조한다.

17.4. 지연 시간 Spin Bit

1-RTT 패킷에 대해 정의된 지연 시간 spin bit(Section 17.3.1)는 연결 기간 전체에 걸쳐 네트워크 경로상의 관찰 지점에서 수동 지연 시간 모니터링을 가능하게 한다. 서버는 수신한 spin 값을 반영하고, 클라이언트는 한 RTT 후에 이를 "회전"시킨다. 경로상 관찰자는 두 spin bit 토글 이벤트 사이의 시간을 측정하여 연결의 종단 간 RTT를 추정할 수 있다.

핸드셰이크를 관찰하여 연결의 초기 RTT를 측정할 수 있으므로, spin bit는 1-RTT 패킷에만 존재한다. 따라서 spin bit는 버전 협상과 연결 설정이 완료된 후 사용할 수 있다. 경로상 측정과 지연 시간 spin bit의 사용은 [QUIC-MANAGEABILITY]에서 추가로 논의된다.

spin bit는 이 QUIC 버전의 OPTIONAL 기능이다. 이 기능을 지원하지 않는 엔드포인트는 아래에 정의된 대로 이를 비활성화해야 MUST 한다.

각 엔드포인트는 연결에 대해 spin bit를 활성화할지 비활성화할지 독립적으로 결정한다. 구현은 클라이언트와 서버의 관리자가 전역적으로 또는 연결별로 spin bit를 비활성화할 수 있게 해야 MUST 한다. 관리자가 spin bit를 비활성화하지 않았더라도, 엔드포인트는 spin bit를 비활성화한 QUIC 연결이 네트워크에서 일반적으로 관찰되도록 보장하기 위해, 네트워크 경로 16개 중 최소 하나의 무작위 선택 또는 연결 ID 16개 중 하나에 대해 spin bit 사용을 비활성화해야 MUST 한다. 각 엔드포인트가 독립적으로 spin bit를 비활성화하므로, 이는 spin bit 신호가 대략 네트워크 경로 8개 중 하나에서 비활성화되도록 보장한다.

spin bit가 비활성화되면, 엔드포인트는 spin bit를 어떤 값으로도 설정할 수 MAY 있으며 들어오는 값을 무시해야 MUST 한다. 엔드포인트는 각 패킷마다 독립적으로 선택하거나 각 연결 ID마다 독립적으로 선택한 무작위 값으로 spin bit를 설정하는 것이 RECOMMENDED 된다.

연결에 대해 spin bit가 활성화된 경우, 엔드포인트는 각 네트워크 경로에 대한 spin 값을 유지하고 해당 경로에서 1-RTT 패킷이 전송될 때 패킷 헤더의 spin bit를 현재 저장된 값으로 설정한다. spin 값은 각 네트워크 경로에 대해 엔드포인트에서 0으로 초기화된다. 각 엔드포인트는 또한 각 경로에서 피어로부터 본 가장 큰 패킷 번호를 기억한다.

서버가 주어진 네트워크 경로에서 클라이언트로부터 서버가 본 가장 큰 패킷 번호를 증가시키는 1-RTT 패킷을 수신하면, 그 경로의 spin 값을 수신한 패킷의 spin bit와 같게 설정한다.

클라이언트가 주어진 네트워크 경로에서 서버로부터 클라이언트가 본 가장 큰 패킷 번호를 증가시키는 1-RTT 패킷을 수신하면, 그 경로의 spin 값을 수신한 패킷의 spin bit의 반대로 설정한다.

엔드포인트는 해당 네트워크 경로에서 사용 중인 연결 ID를 변경할 때 그 네트워크 경로의 spin 값을 0으로 재설정한다.

18. 전송 매개변수 인코딩

[QUIC-TLS]에 정의된 quic_transport_parameters 확장의 extension_data 필드는 QUIC 전송 매개변수를 포함한다. 이들은 Figure 20에 표시된 것처럼 전송 매개변수의 시퀀스로 인코딩된다:

Transport Parameters {
  Transport Parameter (..) ...,
}
Figure 20: 전송 매개변수의 시퀀스

각 전송 매개변수는 Figure 21에 표시된 것처럼 (identifier, length, value) 튜플로 인코딩된다:

Transport Parameter {
  Transport Parameter ID (i),
  Transport Parameter Length (i),
  Transport Parameter Value (..),
}
Figure 21: 전송 매개변수 인코딩

Transport Parameter Length 필드는 Transport Parameter Value 필드의 길이를 바이트 단위로 포함한다.

QUIC는 전송 매개변수를 바이트 시퀀스로 인코딩하며, 이 시퀀스는 이후 암호화 핸드셰이크에 포함된다.

18.1. 예약된 전송 매개변수

정수 값 N에 대해 31 * N + 27 형식의 식별자를 가진 전송 매개변수는 알 수 없는 전송 매개변수가 무시되어야 한다는 요구사항을 실행하기 위해 예약되어 있다. 이러한 전송 매개변수는 의미론이 없으며 임의의 값을 운반할 수 있다.

18.2. 전송 매개변수 정의

이 섹션은 이 문서에 정의된 전송 매개변수를 자세히 설명한다.

여기에 나열된 많은 전송 매개변수는 정수 값을 가진다. 정수로 식별된 전송 매개변수는 가변 길이 정수 인코딩을 사용한다. Section 16을 참조한다. 달리 명시되지 않는 한, 전송 매개변수가 없으면 전송 매개변수의 기본값은 0이다.

다음 전송 매개변수가 정의된다:

original_destination_connection_id (0x00):

이 매개변수는 클라이언트가 보낸 첫 Initial 패킷의 Destination Connection ID 필드 값이다. Section 7.3을 참조한다. 이 전송 매개변수는 서버에 의해서만 전송된다.

max_idle_timeout (0x01):

최대 유휴 타임아웃은 밀리초 단위의 값이며 정수로 인코딩된다. (Section 10.1)을 참조한다. 두 엔드포인트가 모두 이 전송 매개변수를 생략하거나 0 값을 지정하면 유휴 타임아웃은 비활성화된다.

stateless_reset_token (0x02):

stateless reset token은 상태 없는 재설정을 검증하는 데 사용된다. Section 10.3을 참조한다. 이 매개변수는 16바이트 시퀀스이다. 이 전송 매개변수는 클라이언트가 보내서는 MUST NOT 안 되지만 서버가 보낼 수 MAY 있다. 이 전송 매개변수를 보내지 않는 서버는 핸드셰이크 중 협상된 연결 ID에 대해 상태 없는 재설정 (Section 10.3)을 사용할 수 없다.

max_udp_payload_size (0x03):

최대 UDP 페이로드 크기 매개변수는 엔드포인트가 수신할 의향이 있는 UDP 페이로드 크기를 제한하는 정수 값이다. 이 한도보다 큰 페이로드를 가진 UDP 데이터그램은 수신자에 의해 처리될 가능성이 낮다.

이 매개변수의 기본값은 허용되는 최대 UDP 페이로드인 65527이다. 1200보다 작은 값은 유효하지 않다.

이 한도는 경로 MTU와 같은 방식으로 데이터그램 크기에 대한 추가 제약으로 작용하지만, 이는 경로의 속성이 아니라 엔드포인트의 속성이다. Section 14를 참조한다. 이는 엔드포인트가 들어오는 패킷을 보관하기 위해 할당하는 공간으로 기대된다.

initial_max_data (0x04):

초기 최대 데이터 매개변수는 연결에서 보낼 수 있는 데이터의 최대량에 대한 초기값을 포함하는 정수 값이다. 이는 핸드셰이크 완료 직후 연결에 대해 MAX_DATA(Section 19.9)를 보내는 것과 같다.

initial_max_stream_data_bidi_local (0x05):

이 매개변수는 로컬에서 시작된 양방향 스트림의 초기 흐름 제어 한도를 지정하는 정수 값이다. 이 한도는 전송 매개변수를 보내는 엔드포인트가 연 새로 생성된 양방향 스트림에 적용된다. 클라이언트 전송 매개변수에서는 식별자의 최하위 두 비트가 0x00으로 설정된 스트림에 적용되고, 서버 전송 매개변수에서는 최하위 두 비트가 0x01로 설정된 스트림에 적용된다.

initial_max_stream_data_bidi_remote (0x06):

이 매개변수는 피어가 시작한 양방향 스트림의 초기 흐름 제어 한도를 지정하는 정수 값이다. 이 한도는 전송 매개변수를 수신하는 엔드포인트가 연 새로 생성된 양방향 스트림에 적용된다. 클라이언트 전송 매개변수에서는 식별자의 최하위 두 비트가 0x01로 설정된 스트림에 적용되고, 서버 전송 매개변수에서는 최하위 두 비트가 0x00으로 설정된 스트림에 적용된다.

initial_max_stream_data_uni (0x07):

이 매개변수는 단방향 스트림의 초기 흐름 제어 한도를 지정하는 정수 값이다. 이 한도는 전송 매개변수를 수신하는 엔드포인트가 연 새로 생성된 단방향 스트림에 적용된다. 클라이언트 전송 매개변수에서는 식별자의 최하위 두 비트가 0x03으로 설정된 스트림에 적용되고, 서버 전송 매개변수에서는 최하위 두 비트가 0x02로 설정된 스트림에 적용된다.

initial_max_streams_bidi (0x08):

초기 최대 양방향 스트림 매개변수는 이 전송 매개변수를 수신하는 엔드포인트가 시작할 수 있도록 허용된 양방향 스트림의 초기 최대 수를 포함하는 정수 값이다. 이 매개변수가 없거나 0이면, 피어는 MAX_STREAMS 프레임이 전송될 때까지 양방향 스트림을 열 수 없다. 이 매개변수를 설정하는 것은 같은 값을 가진 해당 유형의 MAX_STREAMS(Section 19.11)를 보내는 것과 같다.

initial_max_streams_uni (0x09):

초기 최대 단방향 스트림 매개변수는 이 전송 매개변수를 수신하는 엔드포인트가 시작할 수 있도록 허용된 단방향 스트림의 초기 최대 수를 포함하는 정수 값이다. 이 매개변수가 없거나 0이면, 피어는 MAX_STREAMS 프레임이 전송될 때까지 단방향 스트림을 열 수 없다. 이 매개변수를 설정하는 것은 같은 값을 가진 해당 유형의 MAX_STREAMS(Section 19.11)를 보내는 것과 같다.

ack_delay_exponent (0x0a):

확인 응답 지연 지수는 ACK 프레임(Section 19.3)의 ACK Delay 필드를 디코딩하는 데 사용되는 지수를 나타내는 정수 값이다. 이 값이 없으면 기본값 3이 가정된다(승수 8을 나타냄). 20보다 큰 값은 유효하지 않다.

max_ack_delay (0x0b):

최대 확인 응답 지연은 엔드포인트가 확인 응답 전송을 지연할 최대 시간을 밀리초 단위로 나타내는 정수 값이다. 이 값은 수신자가 예상하는 알람 발생 지연을 포함해야 SHOULD 한다. 예를 들어 수신자가 5ms 타이머를 설정하고 알람이 흔히 최대 1ms 늦게 발생한다면, max_ack_delay를 6ms로 보내야 한다. 이 값이 없으면 기본값 25밀리초가 가정된다. 214 이상의 값은 유효하지 않다.

disable_active_migration (0x0c):

disable active migration 전송 매개변수는 엔드포인트가 핸드셰이크 중 사용되는 주소에서 능동적 연결 마이그레이션 (Section 9)을 지원하지 않는 경우 포함된다. 이 전송 매개변수를 수신한 엔드포인트는 피어가 핸드셰이크 중 사용한 주소로 보낼 때 새 로컬 주소를 사용해서는 MUST NOT 안 된다. 이 전송 매개변수는 클라이언트가 preferred_address 전송 매개변수에 따라 행동한 후의 연결 마이그레이션을 금지하지 않는다. 이 매개변수는 길이가 0인 값이다.

preferred_address (0x0d):

서버의 선호 주소는 Section 9.6에 설명된 것처럼 핸드셰이크 끝에서 서버 주소 변경을 실행하는 데 사용된다. 이 전송 매개변수는 서버에 의해서만 전송된다. 서버는 다른 주소 계열에 대해 모두 0인 주소와 포트(0.0.0.0:0 또는 [::]:0)를 보내 하나의 주소 계열에 대한 선호 주소만 보내도록 선택할 수 MAY 있다. IP 주소는 네트워크 바이트 순서로 인코딩된다.

preferred_address 전송 매개변수는 IPv4와 IPv6 모두에 대한 주소와 포트를 포함한다. 4바이트 IPv4 Address 필드 뒤에는 연결된 2바이트 IPv4 Port 필드가 온다. 그 뒤에는 16바이트 IPv6 Address 필드와 2바이트 IPv6 Port 필드가 온다. 주소와 포트 쌍 뒤에는 Connection ID Length 필드가 이어지는 Connection ID 필드의 길이를 설명한다. 마지막으로 16바이트 Stateless Reset Token 필드는 연결 ID와 연관된 stateless reset token을 포함한다. 이 전송 매개변수의 형식은 아래 Figure 22에 표시되어 있다.

Connection ID 필드와 Stateless Reset Token 필드는 시퀀스 번호 1을 가진 대체 연결 ID를 포함한다. Section 5.1.1을 참조한다. 이러한 값을 선호 주소와 함께 전송하면 클라이언트가 선호 주소로 마이그레이션을 시작할 때 사용되지 않은 활성 연결 ID가 최소 하나 존재하도록 보장된다.

선호 주소의 Connection ID 및 Stateless Reset Token 필드는 NEW_CONNECTION_ID 프레임(Section 19.15)의 해당 필드와 구문 및 의미론이 동일하다. 길이가 0인 연결 ID를 선택한 서버는 선호 주소를 제공해서는 MUST NOT 안 된다. 마찬가지로 서버는 이 전송 매개변수에 길이가 0인 연결 ID를 포함해서는 MUST NOT 안 된다. 클라이언트는 이러한 요구사항의 위반을 TRANSPORT_PARAMETER_ERROR 유형의 연결 오류로 처리해야 MUST 한다.

Preferred Address {
  IPv4 Address (32),
  IPv4 Port (16),
  IPv6 Address (128),
  IPv6 Port (16),
  Connection ID Length (8),
  Connection ID (..),
  Stateless Reset Token (128),
}
Figure 22: Preferred Address 형식
active_connection_id_limit (0x0e):

이는 엔드포인트가 저장할 의향이 있는 피어의 연결 ID 최대 수를 지정하는 정수 값이다. 이 값에는 핸드셰이크 중 수신한 연결 ID, preferred_address 전송 매개변수에서 수신한 연결 ID, 그리고 NEW_CONNECTION_ID 프레임에서 수신한 연결 ID가 포함된다. active_connection_id_limit 매개변수의 값은 최소 2여야 MUST 한다. 2보다 작은 값을 수신한 엔드포인트는 TRANSPORT_PARAMETER_ERROR 유형의 오류로 연결을 닫아야 MUST 한다. 이 전송 매개변수가 없으면 기본값 2가 가정된다. 엔드포인트가 길이가 0인 연결 ID를 발급하면 NEW_CONNECTION_ID 프레임을 보내지 않으므로 피어로부터 수신한 active_connection_id_limit 값을 무시한다.

initial_source_connection_id (0x0f):

이는 엔드포인트가 연결을 위해 보내는 첫 Initial 패킷의 Source Connection ID 필드에 포함한 값이다. Section 7.3을 참조한다.

retry_source_connection_id (0x10):

이는 서버가 Retry 패킷의 Source Connection ID 필드에 포함한 값이다. Section 7.3을 참조한다. 이 전송 매개변수는 서버에 의해서만 전송된다.

존재하는 경우, 초기 스트림별 흐름 제어 한도를 설정하는 전송 매개변수 (initial_max_stream_data_bidi_local, initial_max_stream_data_bidi_remote 및 initial_max_stream_data_uni)는 해당 유형의 모든 스트림에서, 열리자마자 MAX_STREAM_DATA 프레임(Section 19.10)을 보내는 것과 같다. 전송 매개변수가 없으면 해당 유형의 스트림은 흐름 제어 한도 0으로 시작한다.

클라이언트는 서버 전용 전송 매개변수인 original_destination_connection_id, preferred_address, retry_source_connection_id 또는 stateless_reset_token을 포함해서는 MUST NOT 안 된다. 서버는 이러한 전송 매개변수 중 하나라도 수신하면 이를 TRANSPORT_PARAMETER_ERROR 유형의 연결 오류로 처리해야 MUST 한다.

19. 프레임 유형 및 형식

Section 12.4에 설명된 것처럼, 패킷은 하나 이상의 프레임을 포함한다. 이 섹션은 핵심 QUIC 프레임 유형의 형식과 의미론을 설명한다.

19.1. PADDING 프레임

PADDING 프레임(type=0x00)은 의미론적 값을 가지지 않는다. PADDING 프레임은 패킷의 크기를 늘리는 데 사용할 수 있다. 패딩은 Initial 패킷을 필요한 최소 크기로 늘리거나 보호된 패킷에 대한 트래픽 분석 방지를 제공하는 데 사용할 수 있다.

PADDING 프레임은 Figure 23에 표시된 것처럼 형식화되며, 여기서는 PADDING 프레임에 내용이 없음을 보여준다. 즉, PADDING 프레임은 프레임을 PADDING 프레임으로 식별하는 단일 바이트로 구성된다.

PADDING Frame {
  Type (i) = 0x00,
}
Figure 23: PADDING 프레임 형식

19.2. PING 프레임

엔드포인트는 PING 프레임(type=0x01)을 사용하여 피어가 아직 살아 있는지 검증하거나 피어에 대한 도달 가능성을 확인할 수 있다.

PING 프레임은 Figure 24에 표시된 것처럼 형식화되며, 여기서는 PING 프레임에 내용이 없음을 보여준다.

PING Frame {
  Type (i) = 0x01,
}
Figure 24: PING 프레임 형식

PING 프레임의 수신자는 이 프레임을 포함하는 패킷을 확인 응답하기만 하면 된다.

PING 프레임은 애플리케이션 또는 애플리케이션 프로토콜이 연결이 타임아웃되는 것을 방지하려는 경우 연결을 유지하는 데 사용할 수 있다. Section 10.1.2를 참조한다.

19.3. ACK 프레임

수신자는 자신이 수신하고 처리한 패킷을 송신자에게 알리기 위해 ACK 프레임(types 0x02 및 0x03)을 보낸다. ACK 프레임은 하나 이상의 ACK Range를 포함한다. ACK Range는 확인 응답된 패킷을 식별한다. 프레임 유형이 0x03이면 ACK 프레임은 이 시점까지 연결에서 수신된, 관련 ECN 표시가 있는 QUIC 패킷의 누적 카운트도 포함한다. QUIC 구현은 두 유형을 모두 올바르게 처리해야 MUST 하며, 자신이 보내는 패킷에 대해 ECN을 활성화했다면 혼잡 상태를 관리하기 위해 ECN 섹션의 정보를 사용해야 SHOULD 한다.

QUIC 확인 응답은 취소할 수 없다. 일단 확인 응답된 패킷은 향후 ACK 프레임에 나타나지 않더라도 확인 응답된 상태로 남는다. 이는 TCP Selective Acknowledgments(SACKs) [RFC2018]에서의 reneging과 다르다.

서로 다른 패킷 번호 공간의 패킷은 같은 숫자 값을 사용하여 식별될 수 있다. 패킷에 대한 확인 응답은 패킷 번호와 패킷 번호 공간을 모두 나타내야 한다. 이는 각 ACK 프레임이 ACK 프레임이 포함된 패킷과 같은 공간의 패킷 번호만 확인 응답하게 함으로써 달성된다.

Version Negotiation 및 Retry 패킷은 패킷 번호를 포함하지 않으므로 확인 응답될 수 없다. ACK 프레임에 의존하는 대신, 이러한 패킷은 클라이언트가 보내는 다음 Initial 패킷에 의해 암시적으로 확인 응답된다.

ACK 프레임은 Figure 25에 표시된 것처럼 형식화된다.

ACK Frame {
  Type (i) = 0x02..0x03,
  Largest Acknowledged (i),
  ACK Delay (i),
  ACK Range Count (i),
  First ACK Range (i),
  ACK Range (..) ...,
  [ECN Counts (..)],
}
Figure 25: ACK 프레임 형식

ACK 프레임은 다음 필드를 포함한다:

Largest Acknowledged:

피어가 확인 응답하는 가장 큰 패킷 번호를 나타내는 가변 길이 정수이다. 이는 보통 피어가 ACK 프레임을 생성하기 전에 수신한 가장 큰 패킷 번호이다. QUIC 긴 헤더나 짧은 헤더의 패킷 번호와 달리, ACK 프레임의 값은 잘리지 않는다.

ACK Delay:

확인 응답 지연을 마이크로초 단위로 인코딩하는 가변 길이 정수이다. Section 13.2.5를 참조한다. 이는 ACK 프레임의 송신자가 보낸 ack_delay_exponent 전송 매개변수의 거듭제곱인 2를 필드의 값에 곱하여 디코딩된다. Section 18.2를 참조한다. 지연을 단순히 정수로 표현하는 것과 비교할 때, 이 인코딩은 해상도를 낮추는 대신 같은 바이트 수 안에서 더 큰 값 범위를 허용한다.

ACK Range Count:

프레임 안의 ACK Range 필드 수를 지정하는 가변 길이 정수이다.

First ACK Range:

Largest Acknowledged 앞에 연속적으로 있으며 확인 응답되는 패킷 수를 나타내는 가변 길이 정수이다. 즉, 범위에서 확인 응답되는 가장 작은 패킷은 Largest Acknowledged 필드에서 First ACK Range 값을 빼서 결정된다.

ACK Ranges:

확인 응답되지 않은 범위(Gap)와 확인 응답된 범위 (ACK Range)가 번갈아 나타나는 추가 패킷 범위를 포함한다. Section 19.3.1을 참조한다.

ECN Counts:

세 개의 ECN 카운트이다. Section 19.3.2를 참조한다.

19.3.1. ACK 범위

각 ACK Range는 내림차순 패킷 번호 순서의 Gap 및 ACK Range Length 값이 번갈아 나타나는 것으로 구성된다. ACK Range는 반복될 수 있다. Gap 및 ACK Range Length 값의 수는 ACK Range Count 필드에 의해 결정되며, ACK Range Count 필드의 각 값마다 각 값이 하나씩 존재한다.

ACK Range는 Figure 26에 표시된 것처럼 구조화된다.

ACK Range {
  Gap (i),
  ACK Range Length (i),
}
Figure 26: ACK 범위

각 ACK Range를 구성하는 필드는 다음과 같다:

Gap:

이전 ACK Range에서 가장 작은 패킷 번호보다 하나 낮은 패킷 번호 앞에 있는 연속적인 확인 응답되지 않은 패킷 수를 나타내는 가변 길이 정수이다.

ACK Range Length:

이전 Gap에 의해 결정되는 가장 큰 패킷 번호 앞에 있는 연속적인 확인 응답된 패킷 수를 나타내는 가변 길이 정수이다.

Gap 및 ACK Range Length 값은 효율성을 위해 상대 정수 인코딩을 사용한다. 각 인코딩된 값은 양수이지만 값이 빼지므로, 각 ACK Range는 점진적으로 더 낮은 번호의 패킷을 설명한다.

각 ACK Range는 해당 범위에서 가장 큰 패킷 번호 앞에 있는 확인 응답된 패킷 수를 나타내어 연속적인 패킷 범위를 확인 응답한다. 값 0은 가장 큰 패킷 번호만 확인 응답됨을 나타낸다. 더 큰 ACK Range 값은 더 큰 범위를 나타내며, 범위에서 가장 작은 패킷 번호에 해당하는 값은 더 낮아진다. 따라서 범위의 가장 큰 패킷 번호가 주어지면, 가장 작은 값은 다음 공식으로 결정된다:

   smallest = largest - ack_range

ACK Range는 가장 작은 패킷 번호와 가장 큰 패킷 번호 사이의 모든 패킷을 양 끝 포함하여 확인 응답한다.

ACK Range의 가장 큰 값은 앞선 모든 ACK Range Length와 Gap의 크기를 누적하여 빼서 결정된다.

각 Gap은 확인 응답되지 않는 패킷의 범위를 나타낸다. gap 안의 패킷 수는 Gap 필드의 인코딩된 값보다 하나 더 크다.

Gap 필드의 값은 다음 공식을 사용하여 후속 ACK Range의 가장 큰 패킷 번호 값을 설정한다:

   largest = previous_smallest - gap - 2

계산된 패킷 번호 중 하나라도 음수이면, 엔드포인트는 FRAME_ENCODING_ERROR 유형의 연결 오류를 생성해야 MUST 한다.

19.3.2. ECN 카운트

ACK 프레임은 type 값의 최하위 비트(즉 type 0x03)를 사용하여 ECN 피드백을 나타내고, 패킷의 IP 헤더에 ECT(0), ECT(1) 또는 ECN-CE의 관련 ECN 코드포인트가 있는 QUIC 패킷 수신을 보고한다. ECN 카운트는 ACK 프레임 유형이 0x03일 때만 존재한다.

존재하는 경우, Figure 27에 표시된 것처럼 세 개의 ECN 카운트가 있다.

ECN Counts {
  ECT0 Count (i),
  ECT1 Count (i),
  ECN-CE Count (i),
}
Figure 27: ECN 카운트 형식

ECN 카운트 필드는 다음과 같다:

ECT0 Count:

ACK 프레임의 패킷 번호 공간에서 ECT(0) 코드포인트를 가진 상태로 수신된 총 패킷 수를 나타내는 가변 길이 정수이다.

ECT1 Count:

ACK 프레임의 패킷 번호 공간에서 ECT(1) 코드포인트를 가진 상태로 수신된 총 패킷 수를 나타내는 가변 길이 정수이다.

ECN-CE Count:

ACK 프레임의 패킷 번호 공간에서 ECN-CE 코드포인트를 가진 상태로 수신된 총 패킷 수를 나타내는 가변 길이 정수이다.

ECN 카운트는 각 패킷 번호 공간마다 별도로 유지된다.

19.4. RESET_STREAM 프레임

엔드포인트는 RESET_STREAM 프레임(type=0x04)을 사용하여 스트림의 송신 부분을 갑작스럽게 종료한다.

RESET_STREAM을 보낸 후 엔드포인트는 식별된 스트림에서 STREAM 프레임의 전송 및 재전송을 중단한다. RESET_STREAM 수신자는 해당 스트림에서 이미 수신한 모든 데이터를 폐기할 수 있다.

send-only 스트림에 대한 RESET_STREAM 프레임을 수신한 엔드포인트는 STREAM_STATE_ERROR 오류로 연결을 종료해야 MUST 한다.

RESET_STREAM 프레임은 Figure 28에 표시된 것처럼 형식화된다.

RESET_STREAM Frame {
  Type (i) = 0x04,
  Stream ID (i),
  Application Protocol Error Code (i),
  Final Size (i),
}
Figure 28: RESET_STREAM 프레임 형식

RESET_STREAM 프레임은 다음 필드를 포함한다:

Stream ID:

종료되는 스트림의 스트림 ID를 인코딩한 가변 길이 정수이다.

Application Protocol Error Code:

스트림이 닫히는 이유를 나타내는 애플리케이션 프로토콜 오류 코드(Section 20.2 참조)를 포함하는 가변 길이 정수이다.

Final Size:

RESET_STREAM 송신자가 지정하는 스트림의 최종 크기를 바이트 단위로 나타내는 가변 길이 정수이다. Section 4.5를 참조한다.

19.5. STOP_SENDING 프레임

엔드포인트는 STOP_SENDING 프레임(type=0x05)을 사용하여 애플리케이션 요청에 따라 수신 데이터가 수신 시 폐기되고 있음을 전달한다. STOP_SENDING은 피어에게 스트림에서 전송을 중단하도록 요청한다.

STOP_SENDING 프레임은 "Recv" 또는 "Size Known" 상태의 스트림에 대해 보낼 수 있다. Section 3.2를 참조한다. 아직 생성되지 않은 로컬 시작 스트림에 대한 STOP_SENDING 프레임 수신은 STREAM_STATE_ERROR 유형의 연결 오류로 처리되어야 MUST 한다. receive-only 스트림에 대한 STOP_SENDING 프레임을 수신한 엔드포인트는 STREAM_STATE_ERROR 오류로 연결을 종료해야 MUST 한다.

STOP_SENDING 프레임은 Figure 29에 표시된 것처럼 형식화된다.

STOP_SENDING Frame {
  Type (i) = 0x05,
  Stream ID (i),
  Application Protocol Error Code (i),
}
Figure 29: STOP_SENDING 프레임 형식

STOP_SENDING 프레임은 다음 필드를 포함한다:

Stream ID:

무시되고 있는 스트림의 스트림 ID를 운반하는 가변 길이 정수이다.

Application Protocol Error Code:

송신자가 스트림을 무시하는 애플리케이션 지정 이유를 포함하는 가변 길이 정수이다. Section 20.2를 참조한다.

19.6. CRYPTO 프레임

CRYPTO 프레임(type=0x06)은 암호화 핸드셰이크 메시지를 전송하는 데 사용된다. 이는 0-RTT를 제외한 모든 패킷 유형에서 전송될 수 있다. CRYPTO 프레임은 암호화 프로토콜에 순서가 있는 바이트 스트림을 제공한다. CRYPTO 프레임은 STREAM 프레임과 기능적으로 동일하지만, 스트림 식별자를 가지지 않고, 흐름 제어를 받지 않으며, 선택적 오프셋, 선택적 길이 및 스트림의 끝을 나타내는 표식을 운반하지 않는다는 점이 다르다.

CRYPTO 프레임은 Figure 30에 표시된 것처럼 형식화된다.

CRYPTO Frame {
  Type (i) = 0x06,
  Offset (i),
  Length (i),
  Crypto Data (..),
}
Figure 30: CRYPTO 프레임 형식

CRYPTO 프레임은 다음 필드를 포함한다:

Offset:

이 CRYPTO 프레임의 데이터에 대한 스트림 내 바이트 오프셋을 지정하는 가변 길이 정수이다.

Length:

이 CRYPTO 프레임의 Crypto Data 필드 길이를 지정하는 가변 길이 정수이다.

Crypto Data:

암호화 메시지 데이터이다.

각 암호화 수준에는 별도의 암호화 핸드셰이크 데이터 흐름이 있으며, 각각은 오프셋 0에서 시작한다. 이는 각 암호화 수준이 별도의 CRYPTO 데이터 스트림으로 취급됨을 의미한다.

스트림에서 전달된 가장 큰 오프셋, 즉 오프셋과 데이터 길이의 합은 262-1을 초과할 수 없다. 이 한도를 초과하는 프레임의 수신은 FRAME_ENCODING_ERROR 또는 CRYPTO_BUFFER_EXCEEDED 유형의 연결 오류로 처리되어야 MUST 한다.

데이터가 어떤 스트림에 속하는지 나타내는 스트림 ID를 포함하는 STREAM 프레임과 달리, CRYPTO 프레임은 암호화 수준마다 단일 스트림의 데이터를 운반한다. 스트림에는 명시적인 끝이 없으므로 CRYPTO 프레임에는 FIN 비트가 없다.

19.7. NEW_TOKEN 프레임

서버는 향후 연결을 위한 Initial 패킷의 헤더에 보낼 토큰을 클라이언트에게 제공하기 위해 NEW_TOKEN 프레임(type=0x07)을 보낸다.

NEW_TOKEN 프레임은 Figure 31에 표시된 것처럼 형식화된다.

NEW_TOKEN Frame {
  Type (i) = 0x07,
  Token Length (i),
  Token (..),
}
Figure 31: NEW_TOKEN 프레임 형식

NEW_TOKEN 프레임은 다음 필드를 포함한다:

Token Length:

토큰의 길이를 바이트 단위로 지정하는 가변 길이 정수이다.

Token:

클라이언트가 향후 Initial 패킷에서 사용할 수 있는 불투명 blob이다. 토큰은 비어 있어서는 MUST NOT 안 된다. 클라이언트는 빈 Token 필드가 있는 NEW_TOKEN 프레임 수신을 FRAME_ENCODING_ERROR 유형의 연결 오류로 처리해야 MUST 한다.

프레임을 포함하는 패킷이 잘못 손실된 것으로 판단되면, 클라이언트는 같은 토큰 값을 포함하는 여러 NEW_TOKEN 프레임을 수신할 수 있다. 클라이언트는 중복 값을 폐기할 책임이 있으며, 이러한 값은 연결 시도를 연결하는 데 사용될 수 있다. Section 8.1.3을 참조한다.

클라이언트는 NEW_TOKEN 프레임을 보내서는 MUST NOT 안 된다. 서버는 NEW_TOKEN 프레임 수신을 PROTOCOL_VIOLATION 유형의 연결 오류로 처리해야 MUST 한다.

19.8. STREAM 프레임

STREAM 프레임은 암시적으로 스트림을 생성하고 스트림 데이터를 운반한다. STREAM 프레임의 Type 필드는 0b00001XXX 형식(또는 0x08부터 0x0f까지의 값 집합)을 가진다. 프레임 유형의 하위 세 비트는 프레임에 존재하는 필드를 결정한다:

  • 프레임 유형의 OFF 비트(0x04)는 Offset 필드가 존재함을 나타내기 위해 설정된다. 1로 설정되면 Offset 필드가 존재한다. 0으로 설정되면 Offset 필드는 없고 Stream Data는 오프셋 0에서 시작한다(즉, 프레임이 스트림의 첫 바이트를 포함하거나 데이터가 없는 스트림의 끝을 포함한다).
  • 프레임 유형의 LEN 비트(0x02)는 Length 필드가 존재함을 나타내기 위해 설정된다. 이 비트가 0으로 설정되면 Length 필드는 없고 Stream Data 필드는 패킷 끝까지 확장된다. 이 비트가 1로 설정되면 Length 필드가 존재한다.
  • FIN 비트(0x01)는 프레임이 스트림의 끝을 표시함을 나타낸다. 스트림의 최종 크기는 이 프레임의 오프셋과 길이의 합이다.

엔드포인트는 아직 생성되지 않은 로컬 시작 스트림이나 send-only 스트림에 대한 STREAM 프레임을 수신하면 STREAM_STATE_ERROR 오류로 연결을 종료해야 MUST 한다.

STREAM 프레임은 Figure 32에 표시된 것처럼 형식화된다.

STREAM Frame {
  Type (i) = 0x08..0x0f,
  Stream ID (i),
  [Offset (i)],
  [Length (i)],
  Stream Data (..),
}
Figure 32: STREAM 프레임 형식

STREAM 프레임은 다음 필드를 포함한다:

Stream ID:

스트림의 스트림 ID를 나타내는 가변 길이 정수이다. Section 2.1을 참조한다.

Offset:

이 STREAM 프레임의 데이터에 대한 스트림 내 바이트 오프셋을 지정하는 가변 길이 정수이다. 이 필드는 OFF 비트가 1로 설정되었을 때 존재한다. Offset 필드가 없으면 오프셋은 0이다.

Length:

이 STREAM 프레임의 Stream Data 필드 길이를 지정하는 가변 길이 정수이다. 이 필드는 LEN 비트가 1로 설정되었을 때 존재한다. LEN 비트가 0으로 설정되면 Stream Data 필드는 패킷의 남은 모든 바이트를 소비한다.

Stream Data:

전달될 지정된 스트림의 바이트이다.

Stream Data 필드의 길이가 0이면, STREAM 프레임의 오프셋은 다음에 전송될 바이트의 오프셋이다.

스트림의 첫 바이트는 오프셋 0을 가진다. 스트림에서 전달된 가장 큰 오프셋, 즉 오프셋과 데이터 길이의 합은 해당 데이터에 대한 흐름 제어 크레딧을 제공할 수 없으므로 262-1을 초과할 수 없다. 이 한도를 초과하는 프레임의 수신은 FRAME_ENCODING_ERROR 또는 FLOW_CONTROL_ERROR 유형의 연결 오류로 처리되어야 MUST 한다.

19.9. MAX_DATA 프레임

MAX_DATA 프레임(type=0x10)은 흐름 제어에서 연결 전체에서 보낼 수 있는 최대 데이터 양을 피어에게 알리는 데 사용된다.

MAX_DATA 프레임은 Figure 33에 표시된 것처럼 형식화된다.

MAX_DATA Frame {
  Type (i) = 0x10,
  Maximum Data (i),
}
Figure 33: MAX_DATA 프레임 형식

MAX_DATA 프레임은 다음 필드를 포함한다:

Maximum Data:

전체 연결에서 보낼 수 있는 최대 데이터 양을 바이트 단위로 나타내는 가변 길이 정수이다.

STREAM 프레임에서 전송된 모든 데이터는 이 한도에 계산된다. 종료 상태의 스트림을 포함하여 모든 스트림의 최종 크기의 합은 수신자가 광고한 값을 초과해서는 MUST NOT 안 된다. 엔드포인트는 자신이 보낸 maximum data 값보다 더 많은 데이터를 수신하면 FLOW_CONTROL_ERROR 유형의 오류로 연결을 종료해야 MUST 한다. 여기에는 Early Data에서 기억된 한도 위반이 포함된다. Section 7.4.1을 참조한다.

19.10. MAX_STREAM_DATA 프레임

MAX_STREAM_DATA 프레임(type=0x11)은 흐름 제어에서 스트림에서 보낼 수 있는 최대 데이터 양을 피어에게 알리는 데 사용된다.

MAX_STREAM_DATA 프레임은 "Recv" 상태의 스트림에 대해 보낼 수 있다. Section 3.2를 참조한다. 아직 생성되지 않은 로컬 시작 스트림에 대한 MAX_STREAM_DATA 프레임 수신은 STREAM_STATE_ERROR 유형의 연결 오류로 처리되어야 MUST 한다. receive-only 스트림에 대한 MAX_STREAM_DATA 프레임을 수신한 엔드포인트는 STREAM_STATE_ERROR 오류로 연결을 종료해야 MUST 한다.

MAX_STREAM_DATA 프레임은 Figure 34에 표시된 것처럼 형식화된다.

MAX_STREAM_DATA Frame {
  Type (i) = 0x11,
  Stream ID (i),
  Maximum Stream Data (i),
}
Figure 34: MAX_STREAM_DATA 프레임 형식

MAX_STREAM_DATA 프레임은 다음 필드를 포함한다:

Stream ID:

영향받는 스트림의 스트림 ID이며, 가변 길이 정수로 인코딩된다.

Maximum Stream Data:

식별된 스트림에서 보낼 수 있는 최대 데이터 양을 바이트 단위로 나타내는 가변 길이 정수이다.

이 한도에 대해 데이터를 계산할 때, 엔드포인트는 스트림에서 전송되거나 수신된 데이터의 가장 큰 수신 오프셋을 고려한다. 손실이나 재정렬로 인해 스트림에서 가장 큰 수신 오프셋이 해당 스트림에서 수신된 데이터의 총 크기보다 클 수 있다. STREAM 프레임을 수신해도 가장 큰 수신 오프셋이 증가하지 않을 수 있다.

스트림에서 전송되는 데이터는 수신자가 광고한 가장 큰 maximum stream data 값을 초과해서는 MUST NOT 안 된다. 엔드포인트는 영향받는 스트림에 대해 자신이 보낸 가장 큰 maximum stream data보다 더 많은 데이터를 수신하면 FLOW_CONTROL_ERROR 유형의 오류로 연결을 종료해야 MUST 한다. 여기에는 Early Data에서 기억된 한도 위반이 포함된다. Section 7.4.1을 참조한다.

19.11. MAX_STREAMS 프레임

MAX_STREAMS 프레임(type=0x12 또는 0x13)은 피어에게 열 수 있도록 허용된 주어진 유형의 누적 스트림 수를 알린다. type 0x12의 MAX_STREAMS 프레임은 양방향 스트림에 적용되고, type 0x13의 MAX_STREAMS 프레임은 단방향 스트림에 적용된다.

MAX_STREAMS 프레임은 Figure 35에 표시된 것처럼 형식화된다.

MAX_STREAMS Frame {
  Type (i) = 0x12..0x13,
  Maximum Streams (i),
}
Figure 35: MAX_STREAMS 프레임 형식

MAX_STREAMS 프레임은 다음 필드를 포함한다:

Maximum Streams:

연결 수명 동안 열 수 있는 해당 유형의 누적 스트림 수이다. 이 값은 260을 초과할 수 없다. 262-1보다 큰 스트림 ID를 인코딩할 수 없기 때문이다. 이 한도보다 큰 스트림을 여는 것을 허용하는 프레임 수신은 FRAME_ENCODING_ERROR 유형의 연결 오류로 처리되어야 MUST 한다.

손실이나 재정렬은 엔드포인트가 이전에 수신한 것보다 낮은 스트림 한도를 가진 MAX_STREAMS 프레임을 수신하게 할 수 있다. 스트림 한도를 증가시키지 않는 MAX_STREAMS 프레임은 무시되어야 MUST 한다.

엔드포인트는 피어가 설정한 현재 스트림 한도보다 더 많은 스트림을 열어서는 MUST NOT 안 된다. 예를 들어, 단방향 스트림 한도 3을 수신한 서버는 스트림 3, 7, 11을 열 수 있지만 스트림 15는 열 수 없다. 엔드포인트는 피어가 허용된 것보다 더 많은 스트림을 열면 STREAM_LIMIT_ERROR 유형의 오류로 연결을 종료해야 MUST 한다. 여기에는 Early Data에서 기억된 한도 위반이 포함된다. Section 7.4.1을 참조한다.

이러한 프레임(및 해당 전송 매개변수)은 동시에 열 수 있는 스트림 수를 설명하지 않는다는 점에 유의한다. 한도에는 닫힌 스트림뿐 아니라 열린 스트림도 포함된다.

19.12. DATA_BLOCKED 프레임

송신자는 데이터를 보내고자 하지만 연결 수준 흐름 제어 때문에 그렇게 할 수 없을 때 DATA_BLOCKED 프레임(type=0x14)을 보내야 SHOULD 한다. Section 4를 참조한다. DATA_BLOCKED 프레임은 흐름 제어 알고리즘 조정의 입력으로 사용할 수 있다. Section 4.2를 참조한다.

DATA_BLOCKED 프레임은 Figure 36에 표시된 것처럼 형식화된다.

DATA_BLOCKED Frame {
  Type (i) = 0x14,
  Maximum Data (i),
}
Figure 36: DATA_BLOCKED 프레임 형식

DATA_BLOCKED 프레임은 다음 필드를 포함한다:

Maximum Data:

차단이 발생한 연결 수준 한도를 나타내는 가변 길이 정수이다.

19.13. STREAM_DATA_BLOCKED 프레임

송신자는 데이터를 보내고자 하지만 스트림 수준 흐름 제어 때문에 그렇게 할 수 없을 때 STREAM_DATA_BLOCKED 프레임(type=0x15)을 보내야 SHOULD 한다. 이 프레임은 DATA_BLOCKED (Section 19.12)와 유사하다.

send-only 스트림에 대한 STREAM_DATA_BLOCKED 프레임을 수신한 엔드포인트는 STREAM_STATE_ERROR 오류로 연결을 종료해야 MUST 한다.

STREAM_DATA_BLOCKED 프레임은 Figure 37에 표시된 것처럼 형식화된다.

STREAM_DATA_BLOCKED Frame {
  Type (i) = 0x15,
  Stream ID (i),
  Maximum Stream Data (i),
}
Figure 37: STREAM_DATA_BLOCKED 프레임 형식

STREAM_DATA_BLOCKED 프레임은 다음 필드를 포함한다:

Stream ID:

흐름 제어 때문에 차단된 스트림을 나타내는 가변 길이 정수이다.

Maximum Stream Data:

차단이 발생한 스트림의 오프셋을 나타내는 가변 길이 정수이다.

19.14. STREAMS_BLOCKED 프레임

송신자는 스트림을 열고자 하지만 피어가 설정한 최대 스트림 한도 때문에 그렇게 할 수 없을 때 STREAMS_BLOCKED 프레임(type=0x16 또는 0x17)을 보내야 SHOULD 한다. Section 19.11을 참조한다. type 0x16의 STREAMS_BLOCKED 프레임은 양방향 스트림 한도에 도달했음을 나타내는 데 사용되고, type 0x17의 STREAMS_BLOCKED 프레임은 단방향 스트림 한도에 도달했음을 나타내는 데 사용된다.

STREAMS_BLOCKED 프레임은 스트림을 열지 않지만, 새 스트림이 필요했고 스트림 한도가 스트림 생성을 막았음을 피어에게 알린다.

STREAMS_BLOCKED 프레임은 Figure 38에 표시된 것처럼 형식화된다.

STREAMS_BLOCKED Frame {
  Type (i) = 0x16..0x17,
  Maximum Streams (i),
}
Figure 38: STREAMS_BLOCKED 프레임 형식

STREAMS_BLOCKED 프레임은 다음 필드를 포함한다:

Maximum Streams:

프레임이 전송될 당시 허용된 최대 스트림 수를 나타내는 가변 길이 정수이다. 이 값은 260을 초과할 수 없다. 262-1보다 큰 스트림 ID를 인코딩할 수 없기 때문이다. 더 큰 스트림 ID를 인코딩하는 프레임의 수신은 STREAM_LIMIT_ERROR 또는 FRAME_ENCODING_ERROR 유형의 연결 오류로 처리되어야 MUST 한다.

19.15. NEW_CONNECTION_ID 프레임

엔드포인트는 연결을 마이그레이션할 때 연결 가능성을 끊는 데 사용할 수 있는 대체 연결 ID를 피어에게 제공하기 위해 NEW_CONNECTION_ID 프레임(type=0x18)을 보낸다. Section 9.5를 참조한다.

NEW_CONNECTION_ID 프레임은 Figure 39에 표시된 것처럼 형식화된다.

NEW_CONNECTION_ID Frame {
  Type (i) = 0x18,
  Sequence Number (i),
  Retire Prior To (i),
  Length (8),
  Connection ID (8..160),
  Stateless Reset Token (128),
}
Figure 39: NEW_CONNECTION_ID 프레임 형식

NEW_CONNECTION_ID 프레임은 다음 필드를 포함한다:

Sequence Number:

송신자가 연결 ID에 할당한 시퀀스 번호이며, 가변 길이 정수로 인코딩된다. Section 5.1.1을 참조한다.

Retire Prior To:

어떤 연결 ID가 폐기되어야 하는지 나타내는 가변 길이 정수이다. Section 5.1.2를 참조한다.

Length:

연결 ID의 길이를 포함하는 8비트 부호 없는 정수이다. 1보다 작거나 20보다 큰 값은 유효하지 않으며 FRAME_ENCODING_ERROR 유형의 연결 오류로 처리되어야 MUST 한다.

Connection ID:

지정된 길이의 연결 ID이다.

Stateless Reset Token:

연관된 연결 ID가 사용될 때 상태 없는 재설정에 사용될 128비트 값이다. Section 10.3을 참조한다.

엔드포인트는 현재 피어가 길이가 0인 Destination Connection ID로 패킷을 보내야 한다고 요구하는 경우 이 프레임을 보내서는 MUST NOT 안 된다. 연결 ID의 길이를 0으로 또는 0에서 변경하면 연결 ID 값이 언제 변경되었는지 식별하기 어렵다. 길이가 0인 Destination Connection ID로 패킷을 보내는 엔드포인트는 NEW_CONNECTION_ID 프레임 수신을 PROTOCOL_VIOLATION 유형의 연결 오류로 처리해야 MUST 한다.

전송 오류, 타임아웃 및 재전송으로 인해 같은 NEW_CONNECTION_ID 프레임이 여러 번 수신될 수 있다. 같은 프레임을 여러 번 수신하는 것은 연결 오류로 처리되어서는 MUST NOT 안 된다. 수신자는 NEW_CONNECTION_ID 프레임에 제공된 시퀀스 번호를 사용하여 같은 NEW_CONNECTION_ID 프레임을 여러 번 수신하는 것을 처리할 수 있다.

엔드포인트가 이전에 발급된 연결 ID를 다른 Stateless Reset Token 필드 값이나 다른 Sequence Number 필드 값으로 반복하는 NEW_CONNECTION_ID 프레임을 수신하거나, 하나의 시퀀스 번호가 서로 다른 연결 ID에 사용되면, 엔드포인트는 그 수신을 PROTOCOL_VIOLATION 유형의 연결 오류로 처리할 수 MAY 있다.

Retire Prior To 필드는 연결 설정 중 수립된 연결 ID와 preferred_address 전송 매개변수에 적용된다. Section 5.1.2를 참조한다. Retire Prior To 필드의 값은 Sequence Number 필드의 값보다 작거나 같아야 MUST 한다. Retire Prior To 필드에서 Sequence Number 필드의 값보다 큰 값을 수신하는 것은 FRAME_ENCODING_ERROR 유형의 연결 오류로 처리되어야 MUST 한다.

송신자가 Retire Prior To 값을 나타내면, 이후 NEW_CONNECTION_ID 프레임에서 전송되는 더 작은 값은 효과가 없다. 수신자는 수신한 가장 큰 Retire Prior To 값을 증가시키지 않는 모든 Retire Prior To 필드를 무시해야 MUST 한다.

이전에 수신한 NEW_CONNECTION_ID 프레임의 Retire Prior To 필드보다 작은 시퀀스 번호를 가진 NEW_CONNECTION_ID 프레임을 수신한 엔드포인트는, 해당 시퀀스 번호에 대해 이미 그렇게 하지 않았다면 새로 수신한 연결 ID를 폐기하는 해당 RETIRE_CONNECTION_ID 프레임을 보내야 MUST 한다.

19.16. RETIRE_CONNECTION_ID 프레임

엔드포인트는 피어가 발급한 연결 ID를 더 이상 사용하지 않을 것임을 나타내기 위해 RETIRE_CONNECTION_ID 프레임(type=0x19)을 보낸다. 여기에는 핸드셰이크 중 제공된 연결 ID가 포함된다. RETIRE_CONNECTION_ID 프레임을 보내는 것은 또한 향후 사용을 위한 추가 연결 ID를 보내도록 피어에게 요청하는 역할을 한다. Section 5.1을 참조한다. 새 연결 ID는 NEW_CONNECTION_ID 프레임(Section 19.15)을 사용하여 피어에게 전달될 수 있다.

연결 ID를 폐기하면 해당 연결 ID와 연관된 stateless reset token이 무효화된다.

RETIRE_CONNECTION_ID 프레임은 Figure 40에 표시된 것처럼 형식화된다.

RETIRE_CONNECTION_ID Frame {
  Type (i) = 0x19,
  Sequence Number (i),
}
Figure 40: RETIRE_CONNECTION_ID 프레임 형식

RETIRE_CONNECTION_ID 프레임은 다음 필드를 포함한다:

Sequence Number:

폐기되는 연결 ID의 시퀀스 번호이다. Section 5.1.2를 참조한다.

이전에 피어에게 보낸 어떤 것보다 큰 시퀀스 번호를 포함하는 RETIRE_CONNECTION_ID 프레임의 수신은 PROTOCOL_VIOLATION 유형의 연결 오류로 처리되어야 MUST 한다.

RETIRE_CONNECTION_ID 프레임에 지정된 시퀀스 번호는 그 프레임이 포함된 패킷의 Destination Connection ID 필드를 참조해서는 MUST NOT 안 된다. 피어는 이를 PROTOCOL_VIOLATION 유형의 연결 오류로 처리할 수 MAY 있다.

엔드포인트는 피어로부터 길이가 0인 연결 ID를 제공받은 경우 이 프레임을 보낼 수 없다. 길이가 0인 연결 ID를 제공하는 엔드포인트는 RETIRE_CONNECTION_ID 프레임 수신을 PROTOCOL_VIOLATION 유형의 연결 오류로 처리해야 MUST 한다.

19.17. PATH_CHALLENGE 프레임

엔드포인트는 PATH_CHALLENGE 프레임(type=0x1a)을 사용하여 피어에 대한 도달 가능성을 확인하고 연결 마이그레이션 중 경로 검증을 수행할 수 있다.

PATH_CHALLENGE 프레임은 Figure 41에 표시된 것처럼 형식화된다.

PATH_CHALLENGE Frame {
  Type (i) = 0x1a,
  Data (64),
}
Figure 41: PATH_CHALLENGE 프레임 형식

PATH_CHALLENGE 프레임은 다음 필드를 포함한다:

Data:

이 8바이트 필드는 임의의 데이터를 포함한다.

PATH_CHALLENGE 프레임에 64비트 엔트로피를 포함하면 값을 올바르게 추측하는 것보다 패킷을 수신하는 것이 더 쉽도록 보장된다.

이 프레임의 수신자는 같은 Data 값을 포함하는 PATH_RESPONSE 프레임 (Section 19.18)을 생성해야 MUST 한다.

19.18. PATH_RESPONSE 프레임

PATH_RESPONSE 프레임(type=0x1b)은 PATH_CHALLENGE 프레임에 대한 응답으로 전송된다.

PATH_RESPONSE 프레임은 Figure 42에 표시된 것처럼 형식화된다. PATH_RESPONSE 프레임의 형식은 PATH_CHALLENGE 프레임의 형식과 동일하다. Section 19.17을 참조한다.

PATH_RESPONSE Frame {
  Type (i) = 0x1b,
  Data (64),
}
Figure 42: PATH_RESPONSE 프레임 형식

PATH_RESPONSE 프레임의 내용이 엔드포인트가 이전에 보낸 PATH_CHALLENGE 프레임의 내용과 일치하지 않으면, 엔드포인트는 PROTOCOL_VIOLATION 유형의 연결 오류를 생성할 수 MAY 있다.

19.19. CONNECTION_CLOSE 프레임

엔드포인트는 연결이 닫히고 있음을 피어에게 알리기 위해 CONNECTION_CLOSE 프레임(type=0x1c 또는 0x1d)을 보낸다. type 0x1c의 CONNECTION_CLOSE 프레임은 QUIC 계층의 오류만 신호하거나 오류가 없음을(NO_ERROR 코드로) 신호하는 데 사용된다. type 0x1d의 CONNECTION_CLOSE 프레임은 QUIC를 사용하는 애플리케이션의 오류를 신호하는 데 사용된다.

명시적으로 닫히지 않은 열린 스트림이 있으면, 연결이 닫힐 때 이들은 암시적으로 닫힌다.

CONNECTION_CLOSE 프레임은 Figure 43에 표시된 것처럼 형식화된다.

CONNECTION_CLOSE Frame {
  Type (i) = 0x1c..0x1d,
  Error Code (i),
  [Frame Type (i)],
  Reason Phrase Length (i),
  Reason Phrase (..),
}
Figure 43: CONNECTION_CLOSE 프레임 형식

CONNECTION_CLOSE 프레임은 다음 필드를 포함한다:

Error Code:

이 연결을 닫는 이유를 나타내는 가변 길이 정수이다. type 0x1c의 CONNECTION_CLOSE 프레임은 Section 20.1에 정의된 공간의 코드를 사용한다. type 0x1d의 CONNECTION_CLOSE 프레임은 애플리케이션 프로토콜이 정의한 코드를 사용한다. Section 20.2를 참조한다.

Frame Type:

오류를 유발한 프레임의 유형을 인코딩하는 가변 길이 정수이다. 프레임 유형을 알 수 없을 때 값 0(PADDING 프레임 언급과 동등)이 사용된다. 애플리케이션별 CONNECTION_CLOSE 변형(type 0x1d)은 이 필드를 포함하지 않는다.

Reason Phrase Length:

reason phrase의 길이를 바이트 단위로 지정하는 가변 길이 정수이다. CONNECTION_CLOSE 프레임은 패킷 사이에서 분할될 수 없으므로, 패킷 크기에 대한 모든 한도는 reason phrase에 사용할 수 있는 공간도 제한한다.

Reason Phrase:

닫힘에 대한 추가 진단 정보이다. 송신자가 Error Code 값 이상의 세부 정보를 제공하지 않기로 선택하면 길이가 0일 수 있다. 이는 UTF-8로 인코딩된 문자열 [RFC3629]이어야 SHOULD 하지만, 프레임은 언어 태그와 같이 텍스트를 생성한 엔티티 외의 다른 엔티티가 이해하는 데 도움이 되는 정보를 운반하지 않는다.

애플리케이션별 CONNECTION_CLOSE 변형(type 0x1d)은 0-RTT 또는 1-RTT 패킷을 사용해서만 전송될 수 있다. Section 12.5를 참조한다. 애플리케이션이 핸드셰이크 중 연결을 포기하려는 경우, 엔드포인트는 Initial 또는 Handshake 패킷에서 APPLICATION_ERROR 오류 코드가 있는 CONNECTION_CLOSE 프레임(type 0x1c)을 보낼 수 있다.

19.20. HANDSHAKE_DONE 프레임

서버는 HANDSHAKE_DONE 프레임(type=0x1e)을 사용하여 핸드셰이크의 확인을 클라이언트에게 신호한다.

HANDSHAKE_DONE 프레임은 Figure 44에 표시된 것처럼 형식화되며, 여기서는 HANDSHAKE_DONE 프레임에 내용이 없음을 보여준다.

HANDSHAKE_DONE Frame {
  Type (i) = 0x1e,
}
Figure 44: HANDSHAKE_DONE 프레임 형식

HANDSHAKE_DONE 프레임은 서버만 보낼 수 있다. 서버는 핸드셰이크를 완료하기 전에 HANDSHAKE_DONE 프레임을 보내서는 MUST NOT 안 된다. 서버는 HANDSHAKE_DONE 프레임 수신을 PROTOCOL_VIOLATION 유형의 연결 오류로 처리해야 MUST 한다.

19.21. 확장 프레임

QUIC 프레임은 자기 설명적 인코딩을 사용하지 않는다. 따라서 엔드포인트는 패킷을 성공적으로 처리하기 전에 모든 프레임의 구문을 이해해야 한다. 이는 프레임의 효율적인 인코딩을 가능하게 하지만, 엔드포인트가 피어에게 알려지지 않은 유형의 프레임을 보낼 수 없다는 의미이다.

새 유형의 프레임을 사용하려는 QUIC 확장은 먼저 피어가 그 프레임을 이해할 수 있음을 보장해야 MUST 한다. 엔드포인트는 확장 프레임 유형을 수신할 의향을 신호하기 위해 전송 매개변수를 사용할 수 있다. 하나의 전송 매개변수는 하나 이상의 확장 프레임 유형에 대한 지원을 나타낼 수 있다.

핵심 프로토콜 기능(프레임 유형 포함)을 수정하거나 대체하는 확장은, 그 조합의 동작이 명시적으로 정의되지 않는 한 같은 기능을 수정하거나 대체하는 다른 확장과 결합하기 어렵다. 그러한 확장은 같은 프로토콜 구성요소를 수정하는 이전에 정의된 확장과의 상호작용을 정의해야 SHOULD 한다.

확장 프레임은 혼잡 제어를 받아야 MUST 하며 ACK 프레임이 전송되도록 해야 MUST 한다. 예외는 ACK 프레임을 대체하거나 보완하는 확장 프레임이다. 확장 프레임은 확장에서 명시하지 않는 한 흐름 제어에 포함되지 않는다.

프레임 유형 할당을 관리하기 위해 IANA 레지스트리가 사용된다. Section 22.4를 참조한다.

20. 오류 코드

QUIC 전송 오류 코드와 애플리케이션 오류 코드는 62비트 부호 없는 정수이다.

20.1. 전송 오류 코드

이 섹션은 type 0x1c의 CONNECTION_CLOSE 프레임에서 사용할 수 있는 정의된 QUIC 전송 오류 코드를 나열한다. 이러한 오류는 전체 연결에 적용된다.

NO_ERROR (0x00):

엔드포인트는 오류가 없는 상태에서 연결이 갑작스럽게 닫히고 있음을 신호하기 위해 CONNECTION_CLOSE와 함께 이를 사용한다.

INTERNAL_ERROR (0x01):

엔드포인트가 내부 오류를 만나 연결을 계속할 수 없다.

CONNECTION_REFUSED (0x02):

서버가 새 연결 수락을 거부했다.

FLOW_CONTROL_ERROR (0x03):

엔드포인트가 자신이 광고한 데이터 한도에서 허용한 것보다 더 많은 데이터를 수신했다. Section 4를 참조한다.

STREAM_LIMIT_ERROR (0x04):

엔드포인트가 해당 스트림 유형에 대해 광고한 스트림 한도를 초과한 스트림 식별자에 대한 프레임을 수신했다.

STREAM_STATE_ERROR (0x05):

엔드포인트가 해당 프레임을 허용하지 않는 상태의 스트림에 대한 프레임을 수신했다. Section 3을 참조한다.

FINAL_SIZE_ERROR (0x06):

(1) 엔드포인트가 이전에 설정된 최종 크기를 초과하는 데이터를 포함한 STREAM 프레임을 수신했거나, (2) 엔드포인트가 이미 수신된 스트림 데이터의 크기보다 낮은 최종 크기를 포함한 STREAM 프레임 또는 RESET_STREAM 프레임을 수신했거나, (3) 엔드포인트가 이미 설정된 것과 다른 최종 크기를 포함한 STREAM 프레임 또는 RESET_STREAM 프레임을 수신했다.

FRAME_ENCODING_ERROR (0x07):

엔드포인트가 형식이 잘못된 프레임을 수신했다. 예를 들어 알 수 없는 유형의 프레임이나 패킷의 나머지 부분이 운반할 수 있는 것보다 더 많은 확인 응답 범위를 가진 ACK 프레임이 이에 해당한다.

TRANSPORT_PARAMETER_ERROR (0x08):

엔드포인트가 형식이 잘못되었거나, 유효하지 않은 값을 포함했거나, 필수 전송 매개변수를 생략했거나, 금지된 전송 매개변수를 포함했거나, 그 외의 오류가 있는 전송 매개변수를 수신했다.

CONNECTION_ID_LIMIT_ERROR (0x09):

피어가 제공한 연결 ID의 수가 광고된 active_connection_id_limit를 초과했다.

PROTOCOL_VIOLATION (0x0a):

엔드포인트가 더 구체적인 오류 코드로 다루어지지 않는 프로토콜 준수 오류를 감지했다.

INVALID_TOKEN (0x0b):

서버가 유효하지 않은 Token 필드를 포함한 클라이언트 Initial을 수신했다.

APPLICATION_ERROR (0x0c):

애플리케이션 또는 애플리케이션 프로토콜이 연결을 닫게 했다.

CRYPTO_BUFFER_EXCEEDED (0x0d):

엔드포인트가 버퍼링할 수 있는 것보다 더 많은 데이터를 CRYPTO 프레임에서 수신했다.

KEY_UPDATE_ERROR (0x0e):

엔드포인트가 키 업데이트를 수행하는 중 오류를 감지했다. Section 6 of [QUIC-TLS]을 참조한다.

AEAD_LIMIT_REACHED (0x0f):

엔드포인트가 주어진 연결에서 사용되는 AEAD 알고리즘의 기밀성 또는 무결성 한도에 도달했다.

NO_VIABLE_PATH (0x10):

엔드포인트가 네트워크 경로가 QUIC를 지원할 수 없다고 판단했다. 경로가 충분히 큰 MTU를 지원하지 않는 경우를 제외하면, 엔드포인트가 이 코드를 운반하는 CONNECTION_CLOSE 프레임을 수신할 가능성은 낮다.

CRYPTO_ERROR (0x0100-0x01ff):

암호화 핸드셰이크가 실패했다. 사용되는 암호화 핸드셰이크에 특정된 오류 코드를 운반하기 위해 256개 값의 범위가 예약되어 있다. TLS가 암호화 핸드셰이크에 사용될 때 발생하는 오류 코드는 Section 4.8 of [QUIC-TLS]에 설명되어 있다.

새 오류 코드 등록에 대한 자세한 내용은 Section 22.5를 참조한다.

이러한 오류 코드를 정의할 때 여러 원칙이 적용된다. 수신자 측의 특정 조치가 필요할 수 있는 오류 조건에는 고유한 코드가 부여된다. 일반적인 조건을 나타내는 오류에는 특정 코드가 부여된다. 이러한 조건 중 어느 것도 없으면, 흐름 제어나 전송 매개변수 처리처럼 스택의 일반 기능을 식별하는 데 오류 코드가 사용된다. 마지막으로 구현이 더 구체적인 코드를 사용할 수 없거나 사용하려 하지 않는 조건에 대해 일반 오류가 제공된다.

20.2. 애플리케이션 프로토콜 오류 코드

애플리케이션 오류 코드의 관리는 애플리케이션 프로토콜에 맡겨진다. 애플리케이션 프로토콜 오류 코드는 RESET_STREAM 프레임 (Section 19.4), STOP_SENDING 프레임(Section 19.5), 그리고 type 0x1d의 CONNECTION_CLOSE 프레임(Section 19.19)에 사용된다.

21. 보안 고려사항

QUIC의 목표는 안전한 전송 연결을 제공하는 것이다. Section 21.1은 이러한 속성의 개요를 제공하며, 이후 섹션들은 알려진 공격과 대응책의 설명을 포함하여 이러한 속성에 관한 제약과 주의사항을 논의한다.

21.1. 보안 속성 개요

QUIC에 대한 완전한 보안 분석은 이 문서의 범위를 벗어난다. 이 섹션은 구현자를 돕고 프로토콜 분석을 안내하기 위해 원하는 보안 속성을 비공식적으로 설명한다.

QUIC는 [SEC-CONS]에 설명된 위협 모델을 가정하며, 그 모델에서 발생하는 많은 공격에 대한 보호를 제공한다.

이 목적을 위해 공격은 수동 공격과 능동 공격으로 나뉜다. 수동 공격자는 네트워크에서 패킷을 읽을 수 있는 능력을 가지며, 능동 공격자는 네트워크에 패킷을 쓸 수 있는 능력도 가진다. 그러나 수동 공격에는 연결을 구성하는 패킷이 지나가는 경로의 라우팅 변경이나 기타 수정을 유발할 수 있는 능력을 가진 공격자가 포함될 수 있다.

공격자는 추가로 경로상 공격자 또는 경로 밖 공격자로 분류된다. 경로상 공격자는 관찰한 모든 패킷을 읽거나, 수정하거나, 제거하여 그 패킷이 더 이상 목적지에 도달하지 못하게 할 수 있다. 반면 경로 밖 공격자는 패킷을 관찰하지만 원래 패킷이 의도된 목적지에 도달하는 것을 막을 수는 없다. 두 유형의 공격자 모두 임의의 패킷을 전송할 수도 있다. 이 정의는 경로 밖 공격자가 패킷을 관찰할 수 있다는 점에서 Section 3.5 of [SEC-CONS]의 정의와 다르다.

핸드셰이크, 보호된 패킷 및 연결 마이그레이션의 속성은 별도로 고려된다.

21.1.1. 핸드셰이크

QUIC 핸드셰이크는 TLS 1.3 핸드셰이크를 통합하며 Appendix E.1 of [TLS13]에 설명된 암호화 속성을 상속한다. QUIC의 많은 보안 속성은 TLS 핸드셰이크가 이러한 속성을 제공하는 것에 의존한다. TLS 핸드셰이크에 대한 모든 공격은 QUIC에 영향을 줄 수 있다.

세션 키의 비밀성이나 고유성, 또는 참여 피어의 인증을 손상시키는 TLS 핸드셰이크에 대한 모든 공격은 해당 키에 의존하는 QUIC가 제공하는 다른 보안 보장에 영향을 준다. 예를 들어 마이그레이션(Section 9)은 네트워크 경로 간 연결 가능성을 피하기 위해 TLS 핸드셰이크를 통한 키 협상과 QUIC 패킷 보호 모두에서 기밀성 보호의 효과에 의존한다.

TLS 핸드셰이크의 무결성에 대한 공격은 공격자가 애플리케이션 프로토콜 또는 QUIC 버전 선택에 영향을 주게 할 수 있다.

TLS가 제공하는 속성에 더해, QUIC 핸드셰이크는 핸드셰이크에 대한 DoS 공격에 어느 정도 방어를 제공한다.

21.1.1.1. 증폭 방지

주소 검증(Section 8)은 주어진 주소를 주장하는 엔티티가 해당 주소에서 패킷을 수신할 수 있는지 검증하는 데 사용된다. 주소 검증은 증폭 공격 대상을 공격자가 패킷을 관찰할 수 있는 주소로 제한한다.

주소 검증 이전에는 엔드포인트가 보낼 수 있는 양이 제한된다. 엔드포인트는 검증되지 않은 주소로 해당 주소에서 수신한 데이터의 세 배를 초과하여 데이터를 보낼 수 없다.

21.1.1.2. 서버 측 DoS

전체 핸드셰이크에 대한 서버의 첫 flight를 계산하는 것은 잠재적으로 비용이 크며, 서명과 키 교환 계산을 모두 요구한다. 계산 DoS 공격을 방지하기 위해 Retry 패킷은 서버가 비용이 큰 계산을 수행하기 전에 단일 왕복의 비용으로 클라이언트의 IP 주소를 검증할 수 있게 하는 저렴한 토큰 교환 메커니즘을 제공한다. 성공적인 핸드셰이크 후 서버는 클라이언트에 새 토큰을 발급할 수 있으며, 이는 이 비용을 발생시키지 않고 새 연결 설정을 허용한다.

21.1.1.3. 경로상 핸드셰이크 종료

경로상 또는 경로 밖 공격자는 Initial 패킷을 대체하거나 경합시켜 핸드셰이크를 실패하게 할 수 있다. 유효한 Initial 패킷이 교환되고 나면, 이후의 Handshake 패킷은 Handshake 키로 보호되며, 경로상 공격자는 엔드포인트가 시도를 포기하게 만들도록 패킷을 삭제하는 것 외에는 핸드셰이크 실패를 강제할 수 없다.

경로상 공격자는 양쪽 패킷의 주소도 대체할 수 있으며, 따라서 클라이언트 또는 서버가 원격 주소에 대해 잘못된 관점을 갖게 할 수 있다. 이러한 공격은 NAT가 수행하는 기능과 구별할 수 없다.

21.1.1.4. 매개변수 협상

전체 핸드셰이크는 암호학적으로 보호되며, Initial 패킷은 버전별 키로 암호화되고 Handshake 및 이후 패킷은 TLS 키 교환에서 파생된 키로 암호화된다. 또한 매개변수 협상은 TLS transcript에 포함되므로 일반적인 TLS 협상과 동일한 무결성 보장을 제공한다. 공격자는 클라이언트의 전송 매개변수를 관찰할 수 있지만(버전별 salt를 알고 있는 한), 서버의 전송 매개변수는 관찰할 수 없고 매개변수 협상에 영향을 줄 수 없다.

연결 ID는 암호화되지 않지만 모든 패킷에서 무결성 보호된다.

이 버전의 QUIC는 버전 협상 메커니즘을 통합하지 않는다. 호환되지 않는 버전의 구현은 단순히 연결 설정에 실패한다.

21.1.2. 보호된 패킷

패킷 보호(Section 12.1)는 Version Negotiation 패킷을 제외한 모든 패킷에 인증 암호화를 적용한다. 다만 Initial 및 Retry 패킷은 버전별 키 자료 사용 때문에 제한된 보호를 가진다. 자세한 내용은 [QUIC-TLS]를 참조한다. 이 섹션은 보호된 패킷에 대한 수동 및 능동 공격을 고려한다.

경로상 공격자와 경로 밖 공격자 모두 관찰한 패킷을 저장하여 향후 패킷 보호에 대한 오프라인 공격에 사용하는 수동 공격을 수행할 수 있다. 이는 어떤 네트워크의 어떤 패킷이든 관찰하는 모든 관찰자에게 해당된다.

연결에 대한 유효한 패킷을 관찰할 수 없는 상태에서 패킷을 주입하는 공격자는 성공할 가능성이 낮다. 패킷 보호는 유효한 패킷이 핸드셰이크 중 설정된 키 자료를 소유한 엔드포인트에 의해서만 생성되도록 보장하기 때문이다. Sections 721.1.1을 참조한다. 마찬가지로, 패킷을 관찰하고 새 데이터를 삽입하거나 해당 패킷의 기존 데이터를 수정하려는 능동 공격자는 Initial 패킷을 제외하면 수신 엔드포인트가 유효하다고 간주하는 패킷을 생성할 수 없어야 한다.

능동 공격자가 전달하거나 주입하는 패킷의 보호되지 않은 부분, 예를 들어 출발지 또는 목적지 주소를 다시 쓰는 스푸핑 공격은 공격자가 원래 엔드포인트로 패킷을 전달할 수 있을 때만 효과적이다. 패킷 보호는 핸드셰이크를 완료한 엔드포인트만 패킷 페이로드를 처리할 수 있도록 보장하며, 유효하지 않은 패킷은 해당 엔드포인트에 의해 무시된다.

공격자는 패킷과 UDP 데이터그램 사이의 경계도 수정할 수 있으며, 여러 패킷이 하나의 데이터그램으로 병합되게 하거나 병합된 패킷을 여러 데이터그램으로 나눌 수 있다. 패딩이 필요한 Initial 패킷을 포함하는 데이터그램을 제외하면, 패킷이 데이터그램에 배치되는 방식을 수정하는 것은 연결에 기능적 영향을 주지 않지만 일부 성능 특성은 변경할 수 있다.

21.1.3. 연결 마이그레이션

연결 마이그레이션(Section 9)은 엔드포인트가 여러 경로의 IP 주소와 포트 사이에서 전환할 수 있는 능력을 제공하며, non-probing 프레임의 송수신에는 한 번에 하나의 경로만 사용한다. 경로 검증(Section 8.2)은 피어가 특정 경로에서 전송된 패킷을 수신할 의향이 있고 수신할 수 있음을 수립한다. 이는 스푸핑된 주소로 전송되는 패킷 수를 제한하여 주소 스푸핑의 영향을 줄이는 데 도움이 된다.

이 섹션은 다양한 유형의 DoS 공격하에서 연결 마이그레이션의 의도된 보안 속성을 설명한다.

21.1.3.1. 경로상 능동 공격

자신이 관찰한 패킷이 의도된 목적지에 더 이상 도달하지 못하게 할 수 있는 공격자는 경로상 공격자로 간주된다. 공격자가 클라이언트와 서버 사이에 존재할 때, 엔드포인트는 주어진 경로에서 연결성을 수립하기 위해 공격자를 통해 패킷을 보내야 한다.

경로상 공격자는 다음을 할 수 있다:

  • 패킷 검사
  • IP 및 UDP 패킷 헤더 수정
  • 새 패킷 주입
  • 패킷 지연
  • 패킷 재정렬
  • 패킷 삭제
  • 패킷 경계에 따라 데이터그램 분할 및 병합

경로상 공격자는 다음을 할 수 없다:

  • 패킷의 인증된 부분을 수정하고 수신자가 그 패킷을 수락하게 하기

경로상 공격자는 자신이 관찰한 패킷을 수정할 기회를 가진다. 그러나 패킷 페이로드가 인증되고 암호화되므로, 패킷의 인증된 부분에 대한 어떤 수정도 수신 엔드포인트가 해당 패킷을 유효하지 않은 것으로 삭제하게 한다.

QUIC는 경로상 공격자의 능력을 다음과 같이 제한하는 것을 목표로 한다:

  1. 경로상 공격자는 연결이 한 경로를 사용하는 것을 막을 수 있으며, 공격자를 포함하지 않는 다른 경로를 사용할 수 없다면 연결이 실패하게 할 수 있다. 이는 모든 패킷을 삭제하거나, 패킷을 복호화 실패하도록 수정하거나, 다른 방법으로 달성할 수 있다.
  2. 경로상 공격자는 자신도 경로상에 있는 새 경로로의 마이그레이션을, 새 경로의 경로 검증이 실패하게 하여 막을 수 있다.
  3. 경로상 공격자는 자신이 경로상에 있지 않은 경로로 클라이언트가 마이그레이션하는 것을 막을 수 없다.
  4. 경로상 공격자는 패킷을 지연시키거나 삭제하여 연결의 처리량을 낮출 수 있다.
  5. 경로상 공격자는 패킷의 인증된 부분을 수정한 패킷을 엔드포인트가 수락하게 할 수 없다.
21.1.3.2. 경로 밖 능동 공격

경로 밖 공격자는 클라이언트와 서버 사이의 경로에 직접 있지는 않지만, 클라이언트와 서버 사이에 전송된 일부 또는 모든 패킷의 복사본을 얻을 수 있다. 또한 이러한 패킷의 복사본을 어느 엔드포인트로든 보낼 수 있다.

경로 밖 공격자는 다음을 할 수 있다:

  • 패킷 검사
  • 새 패킷 주입
  • 주입된 패킷 재정렬

경로 밖 공격자는 다음을 할 수 없다:

  • 엔드포인트가 보낸 패킷 수정
  • 패킷 지연
  • 패킷 삭제
  • 원래 패킷 재정렬

경로 밖 공격자는 자신이 관찰한 패킷의 수정된 복사본을 만들고, 잠재적으로 스푸핑된 출발지 및 목적지 주소와 함께 그 복사본을 네트워크에 주입할 수 있다.

이 논의의 목적상, 경로 밖 공격자는 관찰한 원래 패킷이 도착하기 전에 목적지 엔드포인트에 도달할 수정된 패킷 복사본을 네트워크에 주입할 수 있는 능력이 있다고 가정한다. 달리 말해, 공격자는 엔드포인트 사이의 합법적인 패킷과의 경합에서 지속적으로 "이길" 능력이 있으며, 잠재적으로 원래 패킷이 수신자에 의해 무시되게 할 수 있다.

또한 공격자가 NAT 상태에 영향을 줄 수 있는 데 필요한 자원을 가지고 있다고 가정한다. 특히 공격자는 엔드포인트가 NAT 바인딩을 잃게 하고, 이후 자신의 트래픽에 사용할 같은 포트를 얻을 수 있다.

QUIC는 경로 밖 공격자의 능력을 다음과 같이 제한하는 것을 목표로 한다:

  1. 경로 밖 공격자는 패킷과 경합하여 "제한된" 경로상 공격자가 되려고 시도할 수 있다.
  2. 경로 밖 공격자는 클라이언트와 서버 사이에 개선된 연결성을 제공할 수 있는 한, 출발지 주소가 경로 밖 공격자로 표시된 전달 패킷에 대해 경로 검증이 성공하게 할 수 있다.
  3. 경로 밖 공격자는 핸드셰이크가 완료된 후 연결이 닫히게 할 수 없다.
  4. 경로 밖 공격자는 새 경로를 관찰할 수 없다면 새 경로로의 마이그레이션이 실패하게 할 수 없다.
  5. 경로 밖 공격자는 자신도 경로 밖 공격자인 새 경로로 마이그레이션하는 동안 제한된 경로상 공격자가 될 수 있다.
  6. 경로 밖 공격자는 클라이언트가 원래 사용한 것과 같은 IP 주소 및 포트에서 서버로 패킷을 보내도록 공유 NAT 상태에 영향을 줌으로써 제한된 경로상 공격자가 될 수 있다.
21.1.3.3. 제한된 경로상 능동 공격

제한된 경로상 공격자는 원래 패킷을 복제하고 서버와 클라이언트 사이에서 전달하여 패킷 라우팅을 개선한 경로 밖 공격자이다. 이로 인해 해당 패킷들이 원래 복사본보다 먼저 도착하여 원래 패킷이 목적지 엔드포인트에 의해 삭제된다.

제한된 경로상 공격자는 엔드포인트 사이의 원래 경로에 있지 않으므로, 엔드포인트가 보낸 원래 패킷은 여전히 목적지에 도달한다는 점에서 경로상 공격자와 다르다. 이는 향후 복사된 패킷을 원래 경로보다 빠르게 목적지로 라우팅하지 못하더라도, 원래 패킷이 목적지에 도달하는 것을 막지 못함을 의미한다.

제한된 경로상 공격자는 다음을 할 수 있다:

  • 패킷 검사
  • 새 패킷 주입
  • 암호화되지 않은 패킷 헤더 수정
  • 패킷 재정렬

제한된 경로상 공격자는 다음을 할 수 없다:

  • 원래 경로에서 전송된 패킷보다 늦게 도착하도록 패킷 지연
  • 패킷 삭제
  • 패킷의 인증되고 암호화된 부분을 수정하고 수신자가 그 패킷을 수락하게 하기

제한된 경로상 공격자는 원래 패킷이 중복 패킷보다 먼저 도착하는 지점까지만 패킷을 지연시킬 수 있다. 이는 원래 경로보다 더 나쁜 지연 시간을 가진 라우팅을 제공할 수 없음을 의미한다. 제한된 경로상 공격자가 패킷을 삭제하더라도 원래 복사본은 여전히 목적지 엔드포인트에 도착한다.

QUIC는 제한된 경로 밖 공격자의 능력을 다음과 같이 제한하는 것을 목표로 한다:

  1. 제한된 경로상 공격자는 핸드셰이크가 완료된 후 연결이 닫히게 할 수 없다.
  2. 제한된 경로상 공격자는 클라이언트가 먼저 활동을 재개하는 경우 유휴 연결이 닫히게 할 수 없다.
  3. 제한된 경로상 공격자는 서버가 먼저 활동을 재개하는 경우 유휴 연결이 손실된 것으로 간주되게 할 수 있다.

이러한 보장은 같은 이유로 모든 NAT에 제공되는 보장과 동일하다는 점에 유의한다.

21.2. 핸드셰이크 서비스 거부

암호화되고 인증된 전송으로서, QUIC는 서비스 거부에 대한 다양한 보호를 제공한다. 암호화 핸드셰이크가 완료되면 QUIC 엔드포인트는 인증되지 않은 대부분의 패킷을 폐기하여, 공격자가 기존 연결을 방해할 수 있는 능력을 크게 제한한다.

연결이 설정되면 QUIC 엔드포인트는 일부 인증되지 않은 ICMP 패킷 (Section 14.2.1 참조)을 수락할 수 있지만, 이러한 패킷의 사용은 극히 제한적이다. 엔드포인트가 수락할 수 있는 유일한 다른 패킷 유형은 상태 없는 재설정(Section 10.3)이며, 이는 토큰이 사용될 때까지 비밀로 유지되는 것에 의존한다.

연결 생성 중에 QUIC는 네트워크 경로 밖에서 오는 공격에 대해서만 보호를 제공한다. 모든 QUIC 패킷은 수신자가 자신의 피어로부터 이전 패킷을 보았다는 증거를 포함한다.

핸드셰이크 중에는 주소가 변경될 수 없으므로, 엔드포인트는 다른 네트워크 경로에서 수신된 패킷을 폐기할 수 있다.

Source 및 Destination Connection ID 필드는 핸드셰이크 중 경로 밖 공격에 대한 주요 보호 수단이다. Section 8.1을 참조한다. 이들은 피어가 설정한 값과 일치해야 한다. Initial 및 Stateless Reset을 제외하면, 엔드포인트는 자신이 이전에 선택한 값과 일치하는 Destination Connection ID 필드를 포함하는 패킷만 수락한다. 이는 Version Negotiation 패킷에 제공되는 유일한 보호이다.

Initial 패킷의 Destination Connection ID 필드는 클라이언트가 예측할 수 없도록 선택하며, 이는 추가 목적을 수행한다. 암호화 핸드셰이크를 운반하는 패킷은 이 연결 ID와 QUIC 버전에 특정된 salt에서 파생된 키로 보호된다. 이를 통해 엔드포인트는 암호화 핸드셰이크가 완료된 후 사용하는 것과 같은 프로세스로 수신한 패킷을 인증할 수 있다. 인증할 수 없는 패킷은 폐기된다. 이런 방식으로 패킷을 보호하면 패킷의 송신자가 Initial 패킷을 보았고 이를 이해했다는 강한 보장을 제공한다.

이러한 보호는 연결이 설정되기 전에 QUIC 패킷을 수신할 수 있는 공격자에 대해 효과적이도록 의도된 것이 아니다. 그러한 공격자는 QUIC 엔드포인트가 수락할 패킷을 보낼 가능성이 있다. 이 버전의 QUIC는 이러한 종류의 공격을 감지하려고 시도하지만, 엔드포인트가 복구하기보다는 연결 설정에 실패할 것으로 기대한다. 대부분의 경우 암호화 핸드셰이크 프로토콜 [QUIC-TLS]이 핸드셰이크 중 변조 감지를 담당한다.

엔드포인트는 핸드셰이크 간섭을 감지하고 복구를 시도하기 위해 다른 방법을 사용할 수 있다. 유효하지 않은 패킷은 다른 방법을 사용하여 식별되고 폐기될 수 있지만, 이 문서는 특정 방법을 요구하지 않는다.

21.3. 증폭 공격

공격자는 서버로부터 주소 검증 토큰 (Section 8)을 수신한 뒤, 그 토큰을 얻는 데 사용한 IP 주소를 해제할 수 있다. 나중에 공격자는 같은 주소를 스푸핑하여 서버와 0-RTT 연결을 시작할 수 있으며, 이 주소는 이제 다른 (피해자) 엔드포인트를 가리킬 수 있다. 따라서 공격자는 잠재적으로 서버가 피해자에게 초기 혼잡 윈도우만큼의 데이터를 보내게 할 수 있다.

서버는 주소 검증 토큰의 사용과 수명을 제한하여 이 공격에 대한 완화책을 제공해야 SHOULD 한다. Section 8.1.3을 참조한다.

21.4. 낙관적 ACK 공격

수신하지 않은 패킷에 대해 확인 응답하는 엔드포인트는 혼잡 제어기가 네트워크가 지원하는 것 이상의 속도로 전송을 허용하게 할 수 있다. 엔드포인트는 이 동작을 감지하기 위해 패킷을 보낼 때 패킷 번호를 건너뛸 수 MAY 있다. 그러면 엔드포인트는 PROTOCOL_VIOLATION 유형의 연결 오류로 즉시 연결을 닫을 수 있다. Section 10.2를 참조한다.

21.5. 요청 위조 공격

요청 위조 공격은 엔드포인트가 자신의 피어로 하여금 피해자를 향해 요청을 발행하게 하며, 그 요청을 엔드포인트가 제어하는 경우 발생한다. 요청 위조 공격은 공격자가 아니면 사용할 수 없을 수 있는 피어의 능력에 접근하는 것을 목표로 한다. 네트워킹 프로토콜에서 요청 위조 공격은 흔히 네트워크에서 피어의 위치 때문에 피해자가 피어에게 부여한 암묵적 권한을 악용하는 데 사용된다.

요청 위조가 효과적이려면, 공격자는 피어가 어떤 패킷을 보내고 그 패킷이 어디로 전송되는지에 영향을 줄 수 있어야 한다. 공격자가 제어된 페이로드로 취약한 서비스를 대상으로 삼을 수 있다면, 해당 서비스는 공격자의 피어에게 귀속되지만 공격자가 결정한 동작을 수행할 수 있다.

예를 들어, 웹의 cross-site request forgery [CSRF] 익스플로잇은 클라이언트가 authorization cookies [COOKIE]를 포함하는 요청을 발행하게 하여, 한 사이트가 다른 사이트로 제한되도록 의도된 정보와 동작에 접근할 수 있게 한다.

QUIC는 UDP 위에서 실행되므로, 주요 우려 공격 방식은 공격자가 피어가 UDP 데이터그램을 보내는 주소를 선택하고 그 패킷의 보호되지 않은 내용 일부를 제어할 수 있는 경우이다. QUIC 엔드포인트가 보내는 데이터의 대부분이 보호되므로, 여기에는 암호문에 대한 제어도 포함된다. 공격자가 피어로 하여금 데이터그램의 내용에 기반하여 어떤 동작을 수행할 호스트로 UDP 데이터그램을 보내게 할 수 있다면 공격은 성공한다.

이 섹션은 QUIC가 요청 위조 공격에 사용될 수 있는 방식을 논의한다.

이 섹션은 또한 QUIC 엔드포인트가 구현할 수 있는 제한적인 대응책을 설명한다. 이러한 완화책은 요청 위조 공격의 잠재적 대상이 조치를 취하지 않더라도 QUIC 구현 또는 배포가 독자적으로 사용할 수 있다. 그러나 UDP 기반 서비스가 요청을 적절히 인가하지 않는다면 이러한 대응책은 충분하지 않을 수 있다.

Section 21.5.4에 설명된 마이그레이션 공격은 매우 강력하고 적절한 대응책이 없으므로, QUIC 서버 구현은 공격자가 서버로 하여금 임의의 목적지에 임의의 UDP 페이로드를 생성하게 할 수 있다고 가정해야 한다. QUIC 서버는 ingress filtering [BCP38]을 배포하지 않고 또한 부적절하게 보호된 UDP 엔드포인트가 있는 네트워크에 배포되어서는 SHOULD NOT 안 된다.

클라이언트가 취약한 엔드포인트와 같은 위치에 있지 않음을 보장하는 것은 일반적으로 불가능하지만, 이 버전의 QUIC는 서버가 마이그레이션하는 것을 허용하지 않으므로 클라이언트에 대한 스푸핑된 마이그레이션 공격을 방지한다. 서버 마이그레이션을 허용하는 향후 확장은 위조 공격에 대한 대응책도 정의해야 MUST 한다.

21.5.1. 엔드포인트를 위한 제어 옵션

QUIC는 공격자가 자신의 피어가 UDP 데이터그램을 보내는 위치에 영향을 주거나 제어할 수 있는 몇 가지 기회를 제공한다:

  • 초기 연결 설정(Section 7)에서는, 예를 들어 DNS 레코드를 채움으로써 서버가 클라이언트가 데이터그램을 보내는 위치를 선택할 수 있다;
  • 선호 주소(Section 9.6)에서는 서버가 클라이언트가 데이터그램을 보내는 위치를 선택할 수 있다;
  • 스푸핑된 연결 마이그레이션(Section 9.3.1)에서는 클라이언트가 출발지 주소 스푸핑을 사용하여 서버가 이후 데이터그램을 보내는 위치를 선택할 수 있다; 그리고
  • 스푸핑된 패킷은 서버가 Version Negotiation 패킷을 보내게 할 수 있다(Section 21.5.5).

모든 경우에서, 공격자는 피어가 QUIC를 이해하지 못할 수 있는 피해자에게 데이터그램을 보내게 할 수 있다. 즉, 이러한 패킷은 주소 검증 전에 피어에 의해 전송된다. Section 8을 참조한다.

패킷의 암호화된 부분 밖에서, QUIC는 엔드포인트가 자신의 피어가 보내는 UDP 데이터그램의 내용을 제어할 수 있는 여러 옵션을 제공한다. Destination Connection ID 필드는 피어가 보낸 패킷 초반에 나타나는 바이트에 대한 직접 제어를 제공한다. Section 5.1을 참조한다. Initial 패킷의 Token 필드는 서버가 Initial 패킷의 다른 바이트를 제어할 수 있게 한다. Section 17.2.2를 참조한다.

이 버전의 QUIC에는 패킷의 암호화된 부분에 대한 간접 제어를 방지하는 조치가 없다. 엔드포인트가 피어가 보내는 프레임의 내용, 특히 STREAM 프레임과 같이 애플리케이션 데이터를 전달하는 프레임의 내용을 제어할 수 있다고 가정해야 한다. 이는 어느 정도 애플리케이션 프로토콜의 세부사항에 의존하지만, 많은 프로토콜 사용 맥락에서 어느 정도의 제어가 가능하다. 공격자는 패킷 보호 키에 접근할 수 있으므로, 피어가 향후 패킷을 어떻게 암호화할지 예측할 수 있을 가능성이 높다. 따라서 데이터그램 내용에 대한 성공적인 제어는 공격자가 패킷 번호와 패킷 내 프레임 배치를 어느 정도 신뢰성 있게 예측할 수 있기만 하면 된다.

이 섹션은 데이터그램 내용에 대한 제어를 제한하는 것이 실현 가능하지 않다고 가정한다. 이후 섹션의 완화책은 주소 검증 전에 전송되는 데이터그램이 요청 위조에 사용될 수 있는 방식을 제한하는 데 초점을 둔다.

21.5.2. 클라이언트 Initial 패킷을 사용한 요청 위조

서버로 동작하는 공격자는 자신이 가용성을 광고하는 IP 주소와 포트를 선택할 수 있으므로, 클라이언트의 Initial 패킷은 이러한 종류의 공격에 사용할 수 있다고 가정된다. 핸드셰이크에 내재된 주소 검증은 새 연결의 경우 클라이언트가 QUIC를 이해하지 못하거나 QUIC 연결을 수락할 의향이 없는 목적지로 다른 유형의 패킷을 보내지 않도록 보장한다.

Initial 패킷 보호(Section 5.2 of [QUIC-TLS])는 서버가 클라이언트가 보내는 Initial 패킷의 내용을 제어하기 어렵게 한다. 클라이언트가 예측할 수 없는 Destination Connection ID를 선택하면 서버가 클라이언트의 Initial 패킷에서 암호화된 부분을 전혀 제어할 수 없도록 보장된다.

그러나 Token 필드는 서버 제어에 열려 있으며, 서버가 클라이언트를 사용하여 요청 위조 공격을 수행할 수 있게 한다. NEW_TOKEN 프레임 (Section 8.1.3)으로 제공된 토큰의 사용은 연결 설정 중 요청 위조를 위한 유일한 옵션을 제공한다.

그러나 클라이언트는 NEW_TOKEN 프레임을 사용할 의무가 없다. Token 필드에 의존하는 요청 위조 공격은 NEW_TOKEN 프레임을 수신했을 때와 비교해 서버 주소가 변경된 경우 클라이언트가 빈 Token 필드를 보내면 피할 수 있다.

클라이언트는 서버 주소가 변경되면 NEW_TOKEN 사용을 피할 수 있다. 그러나 Token 필드를 포함하지 않으면 성능에 악영향을 줄 수 있다. 서버는 데이터 전송의 세 배 한도를 초과하는 데이터 전송을 가능하게 하기 위해 NEW_TOKEN에 의존할 수 있다. Section 8.1을 참조한다. 특히 이는 클라이언트가 서버에 데이터를 요청하기 위해 0-RTT를 사용하는 경우에 영향을 준다.

Retry 패킷(Section 17.2.5)을 보내면 서버는 Token 필드를 변경할 수 있는 옵션을 가진다. Retry를 보낸 후 서버는 클라이언트의 이후 Initial 패킷의 Destination Connection ID 필드도 제어할 수 있다. 이는 Initial 패킷의 암호화된 내용에 대한 간접 제어도 가능하게 할 수 있다. 그러나 Retry 패킷 교환은 서버의 주소를 검증하므로, 이후 Initial 패킷을 요청 위조에 사용하는 것을 방지한다.

21.5.3. 선호 주소를 사용한 요청 위조

서버는 선호 주소를 지정할 수 있으며, 클라이언트는 핸드셰이크를 확인한 후 그 주소로 마이그레이션한다. Section 9.6을 참조한다. 클라이언트가 선호 주소로 보내는 패킷의 Destination Connection ID 필드는 요청 위조에 사용될 수 있다.

클라이언트는 해당 주소를 검증하기 전에 선호 주소로 non-probing 프레임을 보내서는 MUST NOT 안 된다. Section 8을 참조한다. 이는 서버가 데이터그램의 암호화된 부분을 제어할 수 있는 옵션을 크게 줄인다.

이 문서는 선호 주소 사용에 특정되고 엔드포인트가 구현할 수 있는 추가 대응책을 제공하지 않는다. Section 21.5.6에 설명된 일반 조치를 추가 완화책으로 사용할 수 있다.

21.5.4. 스푸핑된 마이그레이션을 사용한 요청 위조

클라이언트는 겉보기 연결 마이그레이션의 일부로 스푸핑된 출발지 주소를 제시하여 서버가 해당 주소로 데이터그램을 보내게 할 수 있다.

서버가 이후 이 스푸핑된 주소로 보내는 모든 패킷의 Destination Connection ID 필드는 요청 위조에 사용될 수 있다. 클라이언트는 암호문에도 영향을 줄 수 있을 수 있다.

주소 검증 전에 서버가 해당 주소로 probing 패킷 (Section 9.1)만 보내면, 공격자는 데이터그램의 암호화된 부분에 대해 제한된 제어만 가진다. 그러나 특히 NAT 리바인딩의 경우 이는 성능에 악영향을 줄 수 있다. 서버가 애플리케이션 데이터를 운반하는 프레임을 보내면, 공격자는 데이터그램 내용 대부분을 제어할 수 있을 수 있다.

이 문서는 Section 21.5.6에 설명된 일반 조치를 제외하고 엔드포인트가 구현할 수 있는 특정 대응책을 제공하지 않는다. 그러나 네트워크 수준의 주소 스푸핑 대응책, 특히 ingress filtering [BCP38]은 스푸핑을 사용하고 외부 네트워크에서 시작되는 공격에 특히 효과적이다.

21.5.5. 버전 협상을 사용한 요청 위조

패킷에 스푸핑된 출발지 주소를 제시할 수 있는 클라이언트는 서버가 해당 주소로 Version Negotiation 패킷(Section 17.2.1)을 보내게 할 수 있다.

알 수 없는 버전의 패킷에 대한 연결 ID 필드의 크기 제한이 없기 때문에, 결과 데이터그램에서 클라이언트가 제어하는 데이터의 양이 증가한다. 이 패킷의 첫 바이트는 클라이언트 제어하에 있지 않고 다음 네 바이트는 0이지만, 클라이언트는 다섯 번째 바이트부터 최대 512바이트를 제어할 수 있다.

이 공격에 대한 특정 대응책은 제공되지 않지만, 일반 보호 (Section 21.5.6)가 적용될 수 있다. 이 경우에도 ingress filtering [BCP38]은 효과적이다.

21.5.6. 일반 요청 위조 대응책

요청 위조 공격에 대한 가장 효과적인 방어는 취약한 서비스를 수정하여 강한 인증을 사용하게 하는 것이다. 그러나 이것이 항상 QUIC 배포의 통제 범위 안에 있는 것은 아니다. 이 섹션은 QUIC 엔드포인트가 독자적으로 취할 수 있는 몇 가지 다른 단계를 개괄한다. 이러한 추가 단계는 상황에 따라 정당한 사용을 방해하거나 막을 수 있으므로 모두 재량적이다.

루프백 인터페이스를 통해 제공되는 서비스는 적절한 인증이 없는 경우가 많다. 엔드포인트는 루프백 주소로의 연결 시도나 마이그레이션을 방지할 수 MAY 있다. 같은 서비스가 이전에 다른 인터페이스에서 사용 가능했거나, 루프백이 아닌 주소의 서비스가 해당 주소를 제공한 경우 엔드포인트는 루프백 주소로의 연결이나 마이그레이션을 허용해서는 SHOULD NOT 안 된다. 이러한 기능에 의존하는 엔드포인트는 이러한 보호를 비활성화하는 옵션을 제공할 수 있다.

마찬가지로, 엔드포인트는 전역 주소, unique-local [RFC4193], 또는 비사설 주소에서 링크-로컬 주소 [RFC4291]나 사설 사용 범위의 주소 [RFC1918]로 변경되는 것을 요청 위조 시도로 간주할 수 있다. 엔드포인트는 이러한 주소 사용을 완전히 거부할 수 있지만, 이는 정당한 사용을 방해할 상당한 위험이 있다. 엔드포인트는 특정 범위의 검증되지 않은 주소로 데이터그램을 보내는 것이 안전하지 않음을 나타내는 네트워크에 대한 구체적인 지식이 없는 한 주소 사용을 거부해서는 SHOULD NOT 안 된다.

엔드포인트는 NEW_TOKEN 프레임의 값을 Initial 패킷에 포함하지 않거나, 주소 검증이 완료되기 전 패킷에 probing 프레임만 보내서 요청 위조 위험을 줄이도록 선택할 수 MAY 있다. 이것이 공격자가 Destination Connection ID 필드를 공격에 사용하는 것을 막지는 않는다는 점에 유의한다.

엔드포인트는 요청 위조 공격의 취약한 대상이 될 수 있는 서버의 위치에 대한 구체적인 정보를 가질 것으로 기대되지 않는다. 그러나 시간이 지나면서 공격의 일반적인 대상이 되는 특정 UDP 포트나 공격에 사용되는 데이터그램의 특정 패턴을 식별할 수 있을 수 있다. 엔드포인트는 목적지 주소를 검증하기 전에 이러한 포트로 데이터그램을 보내지 않거나 이러한 패턴과 일치하는 데이터그램을 보내지 않도록 선택할 수 MAY 있다. 엔드포인트는 문제가 있는 것으로 알려진 패턴을 포함하는 연결 ID를 사용하지 않고 폐기할 수 MAY 있다.

21.6. Slowloris 공격

일반적으로 Slowloris [SLOWLORIS]로 알려진 공격은 대상 엔드포인트에 대한 많은 연결을 열린 상태로 유지하고 가능한 한 오래 유지하려고 시도한다. 이러한 공격은 비활성으로 인해 닫히지 않도록 필요한 최소한의 활동을 생성함으로써 QUIC 엔드포인트에 대해 실행될 수 있다. 여기에는 소량의 데이터를 보내거나, 송신 속도를 제어하기 위해 흐름 제어 창을 점진적으로 열거나, 높은 손실률을 시뮬레이션하는 ACK 프레임을 만들어내는 것이 포함될 수 있다.

QUIC 배포는 서버가 허용할 최대 클라이언트 수를 늘리거나, 단일 IP 주소가 만들 수 있는 연결 수를 제한하거나, 연결이 가질 수 있는 최소 전송 속도에 제한을 부과하거나, 엔드포인트가 연결된 상태로 있을 수 있는 시간을 제한하는 등 Slowloris 공격에 대한 완화책을 제공해야 SHOULD 한다.

21.7. 스트림 단편화 및 재조립 공격

악의적인 송신자는 의도적으로 스트림 데이터의 일부를 보내지 않아 수신자가 전송되지 않은 데이터에 대한 리소스를 할당하게 할 수 있다. 이는 수신 버퍼 메모리의 불균형한 할당 및/또는 수신자에서 크고 비효율적인 데이터 구조의 생성을 초래할 수 있다.

악의적인 수신자는 송신자가 확인 응답되지 않은 스트림 데이터를 재전송을 위해 저장하도록 강제하려는 시도로 스트림 데이터를 포함하는 패킷을 의도적으로 확인 응답하지 않을 수 있다.

수신자에 대한 공격은 흐름 제어 창이 사용 가능한 메모리에 대응하면 완화된다. 그러나 일부 수신자는 메모리를 과다 할당하고 실제 사용 가능한 메모리를 초과하는 흐름 제어 오프셋을 전체적으로 광고한다. 과다 할당 전략은 엔드포인트가 잘 동작할 때 더 나은 성능으로 이어질 수 있지만, 엔드포인트를 스트림 단편화 공격에 취약하게 만든다.

QUIC 배포는 스트림 단편화 공격에 대한 완화책을 제공해야 SHOULD 한다. 완화책은 메모리 과다 할당 회피, 추적 데이터 구조의 크기 제한, STREAM 프레임 재조립 지연, 재조립 hole의 나이와 지속 시간에 기반한 휴리스틱 구현, 또는 이들의 조합으로 구성될 수 있다.

21.8. 스트림 커밋먼트 공격

악의적인 엔드포인트는 많은 수의 스트림을 열어 엔드포인트의 상태를 고갈시킬 수 있다. 악의적인 엔드포인트는 TCP의 SYN flooding 공격과 유사한 방식으로 많은 수의 연결에서 이 과정을 반복할 수 있다.

일반적으로 클라이언트는 Section 2.1에 설명된 것처럼 순차적으로 스트림을 연다. 그러나 짧은 간격으로 여러 스트림이 시작되면, 손실이나 재정렬로 인해 스트림을 여는 STREAM 프레임이 순서를 벗어나 수신될 수 있다. 더 높은 번호의 스트림 ID를 수신하면, 수신자는 같은 유형의 사이에 있는 모든 스트림을 열어야 한다. Section 3.2를 참조한다. 따라서 새 연결에서 스트림 4000000을 열면 클라이언트가 시작한 양방향 스트림 100만 1개가 열린다.

활성 스트림의 수는 수신된 MAX_STREAMS 프레임에 의해 업데이트되는 initial_max_streams_bidi 및 initial_max_streams_uni 전송 매개변수에 의해 제한된다. Section 4.6에 설명된 것과 같다. 신중하게 선택된다면 이러한 한도는 스트림 커밋먼트 공격의 영향을 완화한다. 그러나 한도를 너무 낮게 설정하면 애플리케이션이 많은 수의 스트림을 열 것으로 기대하는 경우 성능에 영향을 줄 수 있다.

21.9. 피어 서비스 거부

QUIC와 TLS는 일부 맥락에서 정당한 용도가 있는 프레임이나 메시지를 모두 포함하지만, 이러한 프레임이나 메시지는 연결 상태에 관찰 가능한 영향을 주지 않으면서 피어가 처리 리소스를 소비하게 하는 데 남용될 수 있다.

메시지는 흐름 제어 한도에 작은 증가분을 보내는 것처럼 작거나 중요하지 않은 방식으로 상태를 변경하고 되돌리는 데도 사용될 수 있다.

처리 비용이 대역폭 소비나 상태에 대한 영향과 비교해 불균형하게 크다면, 이는 악의적인 피어가 처리 용량을 고갈시킬 수 있게 할 수 있다.

모든 메시지에는 정당한 용도가 있지만, 구현은 진행 대비 처리 비용을 추적하고, 생산적이지 않은 패킷의 과도한 수량을 공격의 징후로 처리해야 SHOULD 한다. 엔드포인트는 이 조건에 연결 오류로 응답하거나 패킷을 삭제할 수 MAY 있다.

21.10. 명시적 혼잡 알림 공격

경로상 공격자는 IP 헤더의 ECN 필드 값을 조작하여 송신자의 속도에 영향을 줄 수 있다. [RFC3168]은 조작과 그 영향을 더 자세히 논의한다.

제한된 경로상 공격자는 수정된 ECN 필드가 있는 패킷을 복제하고 보내 송신자의 속도에 영향을 줄 수 있다. 수신자가 중복 패킷을 폐기한다면, 공격자가 이 공격에 성공하려면 중복 패킷을 원래 패킷과 경합시켜야 한다. 따라서 QUIC 엔드포인트는 해당 IP 패킷 안의 최소 하나의 QUIC 패킷이 성공적으로 처리되지 않는 한 IP 패킷의 ECN 필드를 무시한다. Section 13.4를 참조한다.

21.11. 상태 없는 재설정 오라클

상태 없는 재설정은 TCP reset injection과 유사한 가능한 서비스 거부 공격을 만든다. 이 공격은 공격자가 선택한 연결 ID를 가진 연결에 대해 상태 없는 재설정 토큰이 생성되게 할 수 있는 경우 가능하다. 이 토큰이 생성되게 할 수 있는 공격자는 같은 연결 ID를 가진 활성 연결을 재설정할 수 있다.

패킷이 정적 키를 공유하는 서로 다른 인스턴스로 라우팅될 수 있다면, 예를 들어 IP 주소나 포트를 변경함으로써, 공격자는 서버가 상태 없는 재설정을 보내게 할 수 있다. 이러한 방식의 서비스 거부를 방어하기 위해, 상태 없는 재설정을 위한 정적 키를 공유하는 엔드포인트 (Section 10.3.2 참조)는 해당 연결이 더 이상 활성 상태가 아닌 경우를 제외하고, 주어진 연결 ID를 가진 패킷이 항상 연결 상태를 가진 인스턴스에 도착하도록 배치되어야 MUST 한다.

더 일반적으로, 서버는 해당 연결 ID를 가진 연결이 같은 정적 키를 사용하는 어떤 엔드포인트에서든 활성 상태일 수 있다면 상태 없는 재설정을 생성해서는 MUST NOT 안 된다.

동적 로드 밸런싱을 사용하는 클러스터의 경우, 활성 인스턴스가 연결 상태를 보유하는 동안 로드 밸런서 구성 변경이 발생할 수 있다. 인스턴스가 연결 상태를 보유하더라도 라우팅 변경과 그 결과인 상태 없는 재설정은 연결 종료로 이어진다. 패킷이 올바른 인스턴스로 라우팅될 가능성이 없다면, 연결이 타임아웃되기를 기다리는 것보다 상태 없는 재설정을 보내는 것이 낫다. 그러나 이는 라우팅이 공격자의 영향을 받을 수 없는 경우에만 허용된다.

21.12. 버전 다운그레이드

이 문서는 두 엔드포인트 사이에서 사용되는 QUIC 버전을 협상하는 데 사용할 수 있는 QUIC Version Negotiation 패킷(Section 6)을 정의한다. 그러나 이 문서는 이 버전과 이후의 향후 버전 사이에서 이 협상이 어떻게 수행될지 지정하지 않는다. 특히 Version Negotiation 패킷은 버전 다운그레이드 공격을 방지하는 메커니즘을 포함하지 않는다. Version Negotiation 패킷을 사용하는 향후 QUIC 버전은 버전 다운그레이드 공격에 강건한 메커니즘을 정의해야 MUST 한다.

21.13. 라우팅에 의한 표적 공격

배포는 공격자가 새 연결을 특정 서버 인스턴스로 표적화할 수 있는 능력을 제한해야 한다. 이상적으로 라우팅 결정은 주소를 포함하여 클라이언트가 선택한 값과 독립적으로 이루어진다. 인스턴스가 선택되면, 이후 패킷이 같은 인스턴스로 라우팅되도록 연결 ID를 선택할 수 있다.

21.14. 트래픽 분석

QUIC 패킷의 길이는 해당 패킷 내용의 길이에 대한 정보를 드러낼 수 있다. PADDING 프레임은 엔드포인트가 패킷 내용의 길이를 어느 정도 숨길 수 있도록 제공된다. Section 19.1을 참조한다.

트래픽 분석을 물리치는 것은 어렵고 활발한 연구 주제이다. 길이는 정보가 유출될 수 있는 유일한 방식이 아니다. 엔드포인트는 패킷의 타이밍과 같은 다른 side channel을 통해서도 민감한 정보를 드러낼 수 있다.

22. IANA 고려사항

이 문서는 QUIC의 코드포인트 관리를 위해 여러 레지스트리를 수립한다. 이러한 레지스트리는 Section 22.1에 정의된 공통 정책 집합에 따라 운영된다.

22.1. QUIC 레지스트리에 대한 등록 정책

모든 QUIC 레지스트리는 코드포인트의 임시 등록과 영구 등록을 모두 허용한다. 이 섹션은 이러한 레지스트리에 공통으로 적용되는 정책을 문서화한다.

22.1.1. 임시 등록

코드포인트의 임시 등록은 QUIC 확장에 대한 사적 사용과 실험을 허용하기 위한 것이다. 임시 등록에는 코드포인트 값과 연락처 정보만 포함하면 된다. 그러나 임시 등록은 회수되어 다른 목적으로 재할당될 수 있다.

임시 등록에는 Section 4.5 of [RFC8126]에 정의된 Expert Review가 필요하다. 지정된 전문가 또는 전문가들은 남은 코드포인트 공간의 과도한 비율을 차지하는 등록이나, 선택된 공간의 첫 번째 미할당 값(Section 22.1.2 참조)에 대한 등록만 거부될 수 있음을 권고받는다.

임시 등록에는 등록이 마지막으로 업데이트된 시점을 나타내는 Date 필드가 포함된다. 임의의 임시 등록에서 날짜를 업데이트하라는 요청은 지정된 전문가(들)의 검토 없이 이루어질 수 있다.

모든 QUIC 레지스트리는 임시 등록을 지원하기 위해 다음 필드를 포함한다:

Value:

할당된 코드포인트.

Status:

"permanent" 또는 "provisional".

Specification:

해당 값에 대해 공개적으로 이용 가능한 명세에 대한 참조.

Date:

등록의 마지막 업데이트 날짜.

Change Controller:

등록의 정의에 책임이 있는 엔티티.

Contact:

등록자에 대한 연락처 세부 정보.

Notes:

등록에 대한 보충 참고 사항.

임시 등록은 Specification 및 Notes 필드와, 영구 등록에 필요할 수 있는 추가 필드를 생략할 수 MAY 있다. Date 필드는 등록 요청의 일부로 필요하지 않으며, 등록이 생성되거나 업데이트된 날짜로 설정된다.

22.1.2. 코드포인트 선택

QUIC 레지스트리에서 코드포인트를 새로 요청할 때는 기존 할당과 선택된 공간의 첫 번째 미할당 코드포인트를 모두 제외한 무작위로 선택된 코드포인트를 사용해야 SHOULD 한다. 여러 코드포인트에 대한 요청은 연속 범위를 사용할 수 MAY 있다. 이는 서로 다른 구현이 같은 코드포인트에 서로 다른 의미를 부여할 위험을 최소화한다.

첫 번째 미할당 코드포인트의 사용은 Standards Action 정책을 통한 할당을 위해 예약된다. Section 4.9 of [RFC8126]을 참조한다. 이러한 값에는 early codepoint assignment 절차 [EARLY-ASSIGN]를 사용할 수 있다.

프레임 유형처럼 가변 길이 정수 (Section 16)로 인코딩되는 코드포인트의 경우, 사용이 더 긴 인코딩을 가지는 데 특별히 민감하지 않다면 네 바이트 또는 여덟 바이트로 인코딩되는 코드포인트(즉, 값 214 이상)를 사용해야 SHOULD 한다.

QUIC 레지스트리에 코드포인트를 등록하는 신청에는 등록의 일부로 요청 코드포인트가 포함될 수 MAY 있다. 코드포인트가 미할당이고 등록 정책의 요구사항이 충족되면, IANA는 선택된 코드포인트를 할당해야 MUST 한다.

22.1.3. 임시 코드포인트 회수

레지스트리 또는 레지스트리의 일부(예: 가변 길이 인코딩을 사용하는 코드포인트의 64-16383 범위)에서 공간을 회수하기 위해 사용되지 않는 임시 등록을 제거하라는 요청이 이루어질 수 있다. 이는 기록된 날짜가 가장 이른 코드포인트에 대해서만 수행되어야 SHOULD 하며, 1년 이내에 업데이트된 항목은 회수되어서는 SHOULD NOT 안 된다.

코드포인트 제거 요청은 지정된 전문가가 검토해야 MUST 한다. 전문가는 해당 코드포인트가 여전히 사용 중인지 판단하려고 시도해야 MUST 한다. 전문가는 등록에 나열된 연락처와, 코드포인트 사용이 알려져 있는지 확인하기 위해 가능한 한 넓은 범위의 프로토콜 구현자에게 연락할 것을 권고받는다. 또한 전문가는 응답을 위해 최소 4주를 허용할 것을 권고받는다.

이 조사로 코드포인트 사용이 식별되거나 등록 업데이트 요청이 이루어진 경우, 코드포인트는 회수되어서는 MUST NOT 안 된다. 대신 등록의 날짜가 업데이트된다. 알게 된 관련 정보를 기록하는 참고 사항이 등록에 추가될 수 있다.

코드포인트 사용이 식별되지 않았고 등록 업데이트 요청도 없었다면, 코드포인트는 레지스트리에서 제거될 수 MAY 있다.

이 검토 및 협의 절차는 임시 등록을 영구 등록으로 변경하라는 요청에도 적용된다. 다만 이 경우 목표는 코드포인트 사용이 없는지 판단하는 것이 아니라, 등록이 배포된 사용을 정확하게 표현하는지 판단하는 것이다.

22.1.4. 영구 등록

QUIC 레지스트리의 영구 등록은 달리 명시되지 않는 한 Specification Required 정책 (Section 4.6 of [RFC8126])을 사용한다. 지정된 전문가 또는 전문가들은 명세가 존재하고 쉽게 접근 가능한지 검증한다. 전문가는 등록이 남용적이거나, 경솔하거나, 능동적으로 해로운 경우가 아니라면(단지 미적으로 불쾌하거나 아키텍처적으로 의심스러운 경우가 아니라) 등록 승인 쪽으로 편향될 것을 권장받는다. 레지스트리 생성은 영구 등록에 대한 추가 제약을 지정할 수 MAY 있다.

레지스트리 생성은 등록이 다른 등록 정책에 의해 관리되는 코드포인트 범위를 식별할 수 MAY 있다. 예를 들어 "QUIC Frame Types" 레지스트리(Section 22.4)는 0부터 63까지 범위의 코드포인트에 대해 더 엄격한 정책을 가진다.

영구 등록에 대한 더 엄격한 요구사항은 영향을 받는 코드포인트에 대한 임시 등록을 막지 않는다. 예를 들어 프레임 유형 61에 대한 임시 등록을 요청할 수 있다.

Standards Track 간행물이 만든 모든 등록은 영구적이어야 MUST 한다.

이 문서의 모든 등록은 permanent 상태가 할당되며, change controller로 IETF를, contact로 QUIC Working Group(quic@ietf.org)을 나열한다.

22.2. QUIC Versions 레지스트리

IANA는 "QUIC" heading 아래에 "QUIC Versions" 레지스트리를 추가했다.

"QUIC Versions" 레지스트리는 32비트 공간을 관리한다. Section 15를 참조한다. 이 레지스트리는 Section 22.1의 등록 정책을 따른다. 이 레지스트리의 영구 등록은 Specification Required 정책 (Section 4.6 of [RFC8126])을 사용하여 할당된다.

프로토콜에 대한 코드포인트 0x00000001은 이 문서에 정의된 프로토콜에 permanent 상태로 할당된다. 코드포인트 0x00000000은 영구적으로 예약되며, 이 코드포인트의 note는 이 버전이 버전 협상을 위해 예약되었음을 나타낸다.

패턴 0x?a?a?a?a를 따르는 모든 코드포인트는 예약되어 있고, IANA에 의해 할당되어서는 MUST NOT 안 되며, 할당된 값 목록에 나타나서는 MUST NOT 안 된다.

22.3. QUIC Transport Parameters 레지스트리

IANA는 "QUIC" heading 아래에 "QUIC Transport Parameters" 레지스트리를 추가했다.

"QUIC Transport Parameters" 레지스트리는 62비트 공간을 관리한다. 이 레지스트리는 Section 22.1의 등록 정책을 따른다. 이 레지스트리의 영구 등록은 Specification Required 정책(Section 4.6 of [RFC8126])을 사용하여 할당된다. 단, 0x00부터 0x3f(16진수)까지의 값은 예외로, [RFC8126]의 Sections 4.94.10에 정의된 Standards Action 또는 IESG Approval을 사용하여 할당된다.

Section 22.1.1에 나열된 필드에 더해, 이 레지스트리의 영구 등록은 다음 필드를 포함해야 MUST 한다:

Parameter Name:

매개변수에 대한 짧은 mnemonic.

이 레지스트리의 초기 내용은 Table 6에 표시되어 있다.

Table 6: 초기 QUIC Transport Parameters 레지스트리 항목
Value Parameter Name Specification
0x00 original_destination_connection_id Section 18.2
0x01 max_idle_timeout Section 18.2
0x02 stateless_reset_token Section 18.2
0x03 max_udp_payload_size Section 18.2
0x04 initial_max_data Section 18.2
0x05 initial_max_stream_data_bidi_local Section 18.2
0x06 initial_max_stream_data_bidi_remote Section 18.2
0x07 initial_max_stream_data_uni Section 18.2
0x08 initial_max_streams_bidi Section 18.2
0x09 initial_max_streams_uni Section 18.2
0x0a ack_delay_exponent Section 18.2
0x0b max_ack_delay Section 18.2
0x0c disable_active_migration Section 18.2
0x0d preferred_address Section 18.2
0x0e active_connection_id_limit Section 18.2
0x0f initial_source_connection_id Section 18.2
0x10 retry_source_connection_id Section 18.2

정수 값 N에 대해 31 * N + 27 형식의 각 값(즉, 27, 58, 89, ...)은 예약된다. 이러한 값은 IANA에 의해 할당되어서는 MUST NOT 안 되며, 할당된 값 목록에 나타나서는 MUST NOT 안 된다.

22.4. QUIC Frame Types 레지스트리

IANA는 "QUIC" heading 아래에 "QUIC Frame Types" 레지스트리를 추가했다.

"QUIC Frame Types" 레지스트리는 62비트 공간을 관리한다. 이 레지스트리는 Section 22.1의 등록 정책을 따른다. 이 레지스트리의 영구 등록은 Specification Required 정책(Section 4.6 of [RFC8126])을 사용하여 할당된다. 단, 0x00부터 0x3f(16진수)까지의 값은 예외로, [RFC8126]의 Sections 4.9 and 4.10에 정의된 Standards Action 또는 IESG Approval을 사용하여 할당된다.

Section 22.1.1에 나열된 필드에 더해, 이 레지스트리의 영구 등록은 다음 필드를 포함해야 MUST 한다:

Frame Type Name:

프레임 유형에 대한 짧은 mnemonic.

Section 22.1의 조언에 더해, 새로운 영구 등록에 대한 명세는 엔드포인트가 식별된 유형의 프레임을 보낼 수 있음을 판단할 수 있는 수단을 설명해야 SHOULD 한다. 대부분의 등록에는 동반되는 전송 매개변수 등록이 기대된다. Section 22.3을 참조한다. 영구 등록에 대한 명세는 또한 프레임 안의 모든 필드의 형식과 할당된 의미론을 설명해야 한다.

이 레지스트리의 초기 내용은 Table 3에 표로 정리되어 있다. 레지스트리는 Table 3의 "Pkts" 및 "Spec" 열을 포함하지 않는다는 점에 유의한다.

22.5. QUIC Transport Error Codes 레지스트리

IANA는 "QUIC" heading 아래에 "QUIC Transport Error Codes" 레지스트리를 추가했다.

"QUIC Transport Error Codes" 레지스트리는 62비트 공간을 관리한다. 이 공간은 서로 다른 정책이 적용되는 세 범위로 나뉜다. 이 레지스트리의 영구 등록은 Specification Required 정책(Section 4.6 of [RFC8126])을 사용하여 할당된다. 단, 0x00부터 0x3f(16진수)까지의 값은 예외로, [RFC8126]의 Sections 4.94.10에 정의된 Standards Action 또는 IESG Approval을 사용하여 할당된다.

Section 22.1.1에 나열된 필드에 더해, 이 레지스트리의 영구 등록은 다음 필드를 포함해야 MUST 한다:

Code:

매개변수에 대한 짧은 mnemonic.

Description:

오류 코드 의미론에 대한 간단한 설명이며, 명세 참조가 제공된 경우 요약일 수 MAY 있다.

이 레지스트리의 초기 내용은 Table 7에 표시되어 있다.

Table 7: 초기 QUIC Transport Error Codes 레지스트리 항목
Value Code Description Specification
0x00 NO_ERROR 오류 없음 Section 20
0x01 INTERNAL_ERROR 구현 오류 Section 20
0x02 CONNECTION_REFUSED 서버가 연결을 거부함 Section 20
0x03 FLOW_CONTROL_ERROR 흐름 제어 오류 Section 20
0x04 STREAM_LIMIT_ERROR 너무 많은 스트림이 열림 Section 20
0x05 STREAM_STATE_ERROR 유효하지 않은 스트림 상태에서 프레임 수신 Section 20
0x06 FINAL_SIZE_ERROR 최종 크기 변경 Section 20
0x07 FRAME_ENCODING_ERROR 프레임 인코딩 오류 Section 20
0x08 TRANSPORT_PARAMETER_ERROR 전송 매개변수의 오류 Section 20
0x09 CONNECTION_ID_LIMIT_ERROR 너무 많은 연결 ID가 수신됨 Section 20
0x0a PROTOCOL_VIOLATION 일반 프로토콜 위반 Section 20
0x0b INVALID_TOKEN 유효하지 않은 Token 수신 Section 20
0x0c APPLICATION_ERROR 애플리케이션 오류 Section 20
0x0d CRYPTO_BUFFER_EXCEEDED CRYPTO 데이터 버퍼 오버플로 Section 20
0x0e KEY_UPDATE_ERROR 유효하지 않은 패킷 보호 업데이트 Section 20
0x0f AEAD_LIMIT_REACHED 패킷 보호 키의 과도한 사용 Section 20
0x10 NO_VIABLE_PATH 사용 가능한 네트워크 경로가 없음 Section 20
0x0100-​0x01ff CRYPTO_ERROR TLS 경고 코드 Section 20

23. 참고문헌

23.1. 규범적 참고문헌

[BCP38]
Ferguson, P. and D. Senie, "IP 출발지 주소 스푸핑을 사용하는 서비스 거부 공격을 물리치기 위한 네트워크 인그레스 필터링", BCP 38, RFC 2827, .
<https://www.rfc-editor.org/info/bcp38>
[DPLPMTUD]
Fairhurst, G., Jones, T., Tüxen, M., Rüngeler, I., and T. Völker, "데이터그램 전송을 위한 패킷화 계층 경로 MTU 탐색", RFC 8899, DOI 10.17487/RFC8899, , <https://www.rfc-editor.org/info/rfc8899>.
[EARLY-ASSIGN]
Cotton, M., "Standards Track Code Point의 초기 IANA 할당", BCP 100, RFC 7120, DOI 10.17487/RFC7120, , <https://www.rfc-editor.org/info/rfc7120>.
[IPv4]
Postel, J., "인터넷 프로토콜", STD 5, RFC 791, DOI 10.17487/RFC0791, , <https://www.rfc-editor.org/info/rfc791>.
[QUIC-INVARIANTS]
Thomson, M., "QUIC의 버전 독립적 속성", RFC 8999, DOI 10.17487/RFC8999, , <https://www.rfc-editor.org/info/rfc8999>.
[QUIC-RECOVERY]
Iyengar, J., Ed. and I. Swett, Ed., "QUIC 손실 감지 및 혼잡 제어", RFC 9002, DOI 10.17487/RFC9002, , <https://www.rfc-editor.org/info/rfc9002>.
[QUIC-TLS]
Thomson, M., Ed. and S. Turner, Ed., "QUIC 보안을 위한 TLS 사용", RFC 9001, DOI 10.17487/RFC9001, , <https://www.rfc-editor.org/info/rfc9001>.
[RFC1191]
Mogul, J. and S. Deering, "경로 MTU 탐색", RFC 1191, DOI 10.17487/RFC1191, , <https://www.rfc-editor.org/info/rfc1191>.
[RFC2119]
Bradner, S., "요구 수준을 나타내기 위해 RFC에서 사용하는 핵심 단어", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/info/rfc2119>.
[RFC3168]
Ramakrishnan, K., Floyd, S., and D. Black, "IP에 명시적 혼잡 알림(ECN) 추가", RFC 3168, DOI 10.17487/RFC3168, , <https://www.rfc-editor.org/info/rfc3168>.
[RFC3629]
Yergeau, F., "UTF-8, ISO 10646의 변환 형식", STD 63, RFC 3629, DOI 10.17487/RFC3629, , <https://www.rfc-editor.org/info/rfc3629>.
[RFC6437]
Amante, S., Carpenter, B., Jiang, S., and J. Rajahalme, "IPv6 Flow Label 명세", RFC 6437, DOI 10.17487/RFC6437, , <https://www.rfc-editor.org/info/rfc6437>.
[RFC8085]
Eggert, L., Fairhurst, G., and G. Shepherd, "UDP 사용 지침", BCP 145, RFC 8085, DOI 10.17487/RFC8085, , <https://www.rfc-editor.org/info/rfc8085>.
[RFC8126]
Cotton, M., Leiba, B., and T. Narten, "RFC에서 IANA 고려사항 섹션을 작성하기 위한 지침", BCP 26, RFC 8126, DOI 10.17487/RFC8126, , <https://www.rfc-editor.org/info/rfc8126>.
[RFC8174]
Leiba, B., "RFC 2119 핵심 단어에서 대문자와 소문자의 모호성", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/info/rfc8174>.
[RFC8201]
McCann, J., Deering, S., Mogul, J., and R. Hinden, Ed., "IP version 6을 위한 경로 MTU 탐색", STD 87, RFC 8201, DOI 10.17487/RFC8201, , <https://www.rfc-editor.org/info/rfc8201>.
[RFC8311]
Black, D., "명시적 혼잡 알림(ECN) 실험에 대한 제한 완화", RFC 8311, DOI 10.17487/RFC8311, , <https://www.rfc-editor.org/info/rfc8311>.
[TLS13]
Rescorla, E., "Transport Layer Security (TLS) Protocol Version 1.3", RFC 8446, DOI 10.17487/RFC8446, , <https://www.rfc-editor.org/info/rfc8446>.
[UDP]
Postel, J., "User Datagram Protocol", STD 6, RFC 768, DOI 10.17487/RFC0768, , <https://www.rfc-editor.org/info/rfc768>.

23.2. 정보성 참고문헌

[AEAD]
McGrew, D., "인증 암호화를 위한 인터페이스와 알고리즘", RFC 5116, DOI 10.17487/RFC5116, , <https://www.rfc-editor.org/info/rfc5116>.
[ALPN]
Friedl, S., Popov, A., Langley, A., and E. Stephan, "Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension", RFC 7301, DOI 10.17487/RFC7301, , <https://www.rfc-editor.org/info/rfc7301>.
[ALTSVC]
Nottingham, M., McManus, P., and J. Reschke, "HTTP 대체 서비스", RFC 7838, DOI 10.17487/RFC7838, , <https://www.rfc-editor.org/info/rfc7838>.
Barth, A., "HTTP 상태 관리 메커니즘", RFC 6265, DOI 10.17487/RFC6265, , <https://www.rfc-editor.org/info/rfc6265>.
[CSRF]
Barth, A., Jackson, C., and J. Mitchell, "cross-site request forgery에 대한 강건한 방어", Proceedings of the 15th ACM conference on Computer and communications security - CCS '08, DOI 10.1145/1455770.1455782, , <https://doi.org/10.1145/1455770.1455782>.
[EARLY-DESIGN]
Roskind, J., "QUIC: UDP 위의 다중화 스트림 전송", , <https://docs.google.com/document/d/1RNHkx_VvKWyWg6Lr8SZ-saqsQx7rFV-ev2jRFUoVD34/edit?usp=sharing>.
[GATEWAY]
Hätönen, S., Nyrhinen, A., Eggert, L., Strowes, S., Sarolahti, P., and M. Kojo, "홈 게이트웨이 특성에 대한 실험적 연구", Proceedings of the 10th ACM SIGCOMM conference on Internet measurement - IMC '10, DOI 10.1145/1879141.1879174, , <https://doi.org/10.1145/1879141.1879174>.
[HTTP2]
Belshe, M., Peon, R., and M. Thomson, Ed., "Hypertext Transfer Protocol Version 2 (HTTP/2)", RFC 7540, DOI 10.17487/RFC7540, , <https://www.rfc-editor.org/info/rfc7540>.
[IPv6]
Deering, S. and R. Hinden, "Internet Protocol, Version 6 (IPv6) 명세", STD 86, RFC 8200, DOI 10.17487/RFC8200, , <https://www.rfc-editor.org/info/rfc8200>.
[QUIC-MANAGEABILITY]
Kuehlewind, M. and B. Trammell, "QUIC 전송 프로토콜의 관리 가능성", Work in Progress, Internet-Draft, draft-ietf-quic-manageability-11, , <https://tools.ietf.org/html/draft-ietf-quic-manageability-11>.
[RANDOM]
Eastlake 3rd, D., Schiller, J., and S. Crocker, "보안을 위한 무작위성 요구사항", BCP 106, RFC 4086, DOI 10.17487/RFC4086, , <https://www.rfc-editor.org/info/rfc4086>.
[RFC1812]
Baker, F., Ed., "IP Version 4 라우터에 대한 요구사항", RFC 1812, DOI 10.17487/RFC1812, , <https://www.rfc-editor.org/info/rfc1812>.
[RFC1918]
Rekhter, Y., Moskowitz, B., Karrenberg, D., de Groot, G. J., and E. Lear, "사설 인터넷을 위한 주소 할당", BCP 5, RFC 1918, DOI 10.17487/RFC1918, , <https://www.rfc-editor.org/info/rfc1918>.
[RFC2018]
Mathis, M., Mahdavi, J., Floyd, S., and A. Romanow, "TCP 선택적 확인 응답 옵션", RFC 2018, DOI 10.17487/RFC2018, , <https://www.rfc-editor.org/info/rfc2018>.
[RFC2104]
Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: 메시지 인증을 위한 키 기반 해싱", RFC 2104, DOI 10.17487/RFC2104, , <https://www.rfc-editor.org/info/rfc2104>.
[RFC3449]
Balakrishnan, H., Padmanabhan, V., Fairhurst, G., and M. Sooriyabandara, "네트워크 경로 비대칭성이 TCP 성능에 미치는 영향", BCP 69, RFC 3449, DOI 10.17487/RFC3449, , <https://www.rfc-editor.org/info/rfc3449>.
[RFC4193]
Hinden, R. and B. Haberman, "Unique Local IPv6 Unicast Addresses", RFC 4193, DOI 10.17487/RFC4193, , <https://www.rfc-editor.org/info/rfc4193>.
[RFC4291]
Hinden, R. and S. Deering, "IP Version 6 주소 지정 아키텍처", RFC 4291, DOI 10.17487/RFC4291, , <https://www.rfc-editor.org/info/rfc4291>.
[RFC4443]
Conta, A., Deering, S., and M. Gupta, Ed., "Internet Protocol Version 6 (IPv6) 명세를 위한 Internet Control Message Protocol (ICMPv6)", STD 89, RFC 4443, DOI 10.17487/RFC4443, , <https://www.rfc-editor.org/info/rfc4443>.
[RFC4787]
Audet, F., Ed. and C. Jennings, "유니캐스트 UDP를 위한 Network Address Translation (NAT) 동작 요구사항", BCP 127, RFC 4787, DOI 10.17487/RFC4787, , <https://www.rfc-editor.org/info/rfc4787>.
[RFC5681]
Allman, M., Paxson, V., and E. Blanton, "TCP 혼잡 제어", RFC 5681, DOI 10.17487/RFC5681, , <https://www.rfc-editor.org/info/rfc5681>.
[RFC5869]
Krawczyk, H. and P. Eronen, "HMAC 기반 Extract-and-Expand Key Derivation Function (HKDF)", RFC 5869, DOI 10.17487/RFC5869, , <https://www.rfc-editor.org/info/rfc5869>.
[RFC7983]
Petit-Huguenin, M. and G. Salgueiro, "Datagram Transport Layer Security (DTLS)를 위한 Secure Real-time Transport Protocol (SRTP) 확장의 다중화 방식 업데이트", RFC 7983, DOI 10.17487/RFC7983, , <https://www.rfc-editor.org/info/rfc7983>.
[RFC8087]
Fairhurst, G. and M. Welzl, "명시적 혼잡 알림(ECN) 사용의 이점", RFC 8087, DOI 10.17487/RFC8087, , <https://www.rfc-editor.org/info/rfc8087>.
[RFC8981]
Gont, F., Krishnan, S., Narten, T., and R. Draves, "IPv6의 Stateless Address Autoconfiguration을 위한 임시 주소 확장", RFC 8981, DOI 10.17487/RFC8981, , <https://www.rfc-editor.org/info/rfc8981>.
[SEC-CONS]
Rescorla, E. and B. Korver, "보안 고려사항에 대한 RFC 텍스트 작성 지침", BCP 72, RFC 3552, DOI 10.17487/RFC3552, , <https://www.rfc-editor.org/info/rfc3552>.
[SLOWLORIS]
"RSnake" Hansen, R., "Slowloris에 오신 것을 환영합니다 - 낮은 대역폭이지만 탐욕스럽고 유독한 HTTP 클라이언트!", , <https://web.archive.org/web/20150315054838/http://ha.ckers.org/slowloris/>.

Appendix A. 의사코드

이 섹션의 의사코드는 예시 알고리즘을 설명한다. 이러한 알고리즘은 최적의 성능을 내기보다는 정확하고 명확하도록 의도되었다.

이 섹션의 의사코드 세그먼트는 Code Components로 라이선스가 부여된다. Copyright Notice를 참조한다.

A.1. 샘플 가변 길이 정수 디코딩

Figure 45의 의사코드는 바이트 스트림에서 가변 길이 정수를 읽는 방법을 보여준다. ReadVarint 함수는 단일 인수, 즉 네트워크 바이트 순서로 읽을 수 있는 바이트 시퀀스를 받는다.

ReadVarint(data):
  // The length of variable-length integers is encoded in the
  // first two bits of the first byte.
  v = data.next_byte()
  prefix = v >> 6
  length = 1 << prefix

  // Once the length is known, remove these bits and read any
  // remaining bytes.
  v = v & 0x3f
  repeat length-1 times:
    v = (v << 8) + data.next_byte()
  return v
Figure 45: 샘플 가변 길이 정수 디코딩 알고리즘

예를 들어, 8바이트 시퀀스 0xc2197c5eff14e88c는 십진수 값 151,288,809,941,952,652로 디코딩된다. 4바이트 시퀀스 0x9d7f3e7d는 494,878,333으로 디코딩된다. 2바이트 시퀀스 0x7bbd는 15,293으로 디코딩된다. 그리고 단일 바이트 0x25는 37로 디코딩된다(2바이트 시퀀스 0x4025도 마찬가지이다).

A.2. 샘플 패킷 번호 인코딩 알고리즘

Figure 46의 의사코드는 구현이 패킷 번호 인코딩에 적절한 크기를 선택하는 방법을 보여준다.

EncodePacketNumber 함수는 두 인수를 받는다:

  • full_pn은 전송되는 패킷의 전체 패킷 번호이다.
  • largest_acked는 현재 패킷 번호 공간에서 피어가 확인 응답한 가장 큰 패킷 번호이며, 있는 경우에 해당한다.
EncodePacketNumber(full_pn, largest_acked):

  // The number of bits must be at least one more
  // than the base-2 logarithm of the number of contiguous
  // unacknowledged packet numbers, including the new packet.
  if largest_acked is None:
    num_unacked = full_pn + 1
  else:
    num_unacked = full_pn - largest_acked

  min_bits = log(num_unacked, 2) + 1
  num_bytes = ceil(min_bits / 8)

  // Encode the integer value and truncate to
  // the num_bytes least significant bytes.
  return encode(full_pn, num_bytes)
Figure 46: 샘플 패킷 번호 인코딩 알고리즘

예를 들어, 엔드포인트가 패킷 0xabe8b3에 대한 확인 응답을 수신했고 번호 0xac5c02인 패킷을 전송하고 있다면, outstanding 패킷 번호는 29,519(0x734f)개이다. 이 범위의 최소 두 배(59,038개 패킷, 즉 0xe69e)를 표현하려면 16비트가 필요하다.

같은 상태에서 번호 0xace8fe인 패킷을 전송하면 24비트 인코딩을 사용한다. 이 범위의 두 배(131,222개 패킷, 즉 0x020096)를 표현하려면 최소 18비트가 필요하기 때문이다.

A.3. 샘플 패킷 번호 디코딩 알고리즘

Figure 47의 의사코드는 헤더 보호가 제거된 후 패킷 번호를 디코딩하는 예시 알고리즘을 포함한다.

DecodePacketNumber 함수는 세 인수를 받는다:

  • largest_pn은 현재 패킷 번호 공간에서 성공적으로 처리된 가장 큰 패킷 번호이다.
  • truncated_pn은 Packet Number 필드의 값이다.
  • pn_nbits는 Packet Number 필드의 비트 수(8, 16, 24 또는 32)이다.
DecodePacketNumber(largest_pn, truncated_pn, pn_nbits):
   expected_pn  = largest_pn + 1
   pn_win       = 1 << pn_nbits
   pn_hwin      = pn_win / 2
   pn_mask      = pn_win - 1
   // The incoming packet number should be greater than
   // expected_pn - pn_hwin and less than or equal to
   // expected_pn + pn_hwin
   //
   // This means we cannot just strip the trailing bits from
   // expected_pn and add the truncated_pn because that might
   // yield a value outside the window.
   //
   // The following code calculates a candidate value and
   // makes sure it's within the packet number window.
   // Note the extra checks to prevent overflow and underflow.
   candidate_pn = (expected_pn & ~pn_mask) | truncated_pn
   if candidate_pn <= expected_pn - pn_hwin and
      candidate_pn < (1 << 62) - pn_win:
      return candidate_pn + pn_win
   if candidate_pn > expected_pn + pn_hwin and
      candidate_pn >= pn_win:
      return candidate_pn - pn_win
   return candidate_pn
Figure 47: 샘플 패킷 번호 디코딩 알고리즘

예를 들어, 성공적으로 인증된 가장 높은 패킷의 패킷 번호가 0xa82f30ea라면, 16비트 값 0x9b32를 포함하는 패킷은 0xa82f9b32로 디코딩된다.

A.4. 샘플 ECN 검증 알고리즘

엔드포인트가 새 네트워크 경로에서 전송을 시작할 때마다, 해당 경로가 ECN을 지원하는지 판단한다. Section 13.4를 참조한다. 경로가 ECN을 지원하면 목표는 ECN을 사용하는 것이다. 엔드포인트는 ECN을 지원하지 않는 것으로 판단된 경로를 주기적으로 재평가할 수도 있다.

이 섹션은 새 경로를 테스트하는 한 가지 방법을 설명한다. 이 알고리즘은 ECN 지원 여부를 경로에서 어떻게 테스트할 수 있는지 보여주기 위한 것이다. 엔드포인트는 다른 방법을 구현할 수 있다.

경로에는 "testing", "unknown", "failed" 또는 "capable" 중 하나인 ECN 상태가 할당된다. "testing" 또는 "capable" 상태의 경로에서는 엔드포인트가 ECT 표시가 있는 패킷을 보낸다. 기본값은 ECT(0)이다. 그렇지 않으면 엔드포인트는 표시되지 않은 패킷을 보낸다.

경로 테스트를 시작하려면 ECN 상태가 "testing"으로 설정되고, 기존 ECN 카운트가 기준선으로 기억된다.

테스트 기간은 엔드포인트가 결정한 패킷 수 또는 제한된 시간 동안 실행된다. 목표는 테스트 기간의 지속 시간을 제한하는 것이 아니라, 수신된 ECN 카운트가 경로가 표시된 패킷을 어떻게 처리하는지에 대한 명확한 표시를 제공할 수 있도록 충분한 표시된 패킷이 전송되도록 보장하는 것이다. Section 13.4.2는 이를 10개 패킷 또는 PTO의 세 배로 제한할 것을 제안한다.

테스트 기간이 끝나면 경로의 ECN 상태는 "unknown"이 된다. "unknown" 상태에서, ACK 프레임의 ECN 카운트 검증 성공(Section 13.4.2.1 참조)은 표시된 패킷이 하나도 확인 응답되지 않은 경우를 제외하고, 경로의 ECN 상태를 "capable"로 만든다.

ECN 카운트 검증이 언제든 실패하면, 영향을 받는 경로의 ECN 상태는 "failed"가 된다. 엔드포인트는 표시된 패킷이 모두 손실로 선언되었거나 모두 ECN-CE 표시가 된 경우에도 경로의 ECN 상태를 "failed"로 표시할 수 있다.

이 알고리즘을 따르면 ECN을 적절히 지원하는 경로에서 ECN이 비활성화되는 경우가 드물도록 보장된다. 표시를 잘못 수정하는 경로는 ECN이 비활성화되게 한다. 표시된 패킷이 경로에서 폐기되는 드문 경우에는, 테스트 기간이 짧아 발생하는 손실 수가 제한된다.

기여자

이 프로토콜의 원래 설계와 그 근거는 Jim Roskind의 작업 [EARLY-DESIGN]에서 상당히 많이 비롯되었다.

IETF QUIC Working Group은 많은 사람들로부터 엄청난 지원을 받았다. 다음 사람들은 이 문서에 실질적인 기여를 제공했다:

저자 주소

Jana Iyengar (편집자)
Fastly
Martin Thomson (편집자)
Mozilla