RFC 9298 Proxying UDP in HTTP August 2022
Schinazi Standards Track [Page]
Stream:
Internet Engineering Task Force (IETF)
RFC:
9298
Category:
Standards Track
Published:
ISSN:
2070-1721
Author:
D. Schinazi
Google LLC

RFC 9298

Proxying UDP in HTTP

요약

이 문서는 HTTP에서 UDP를 프록시하는 방법을 설명합니다. 이는 HTTP CONNECT 메서드가 HTTP에서 TCP를 프록시하는 방식과 유사합니다. 보다 구체적으로, 본 문서는 HTTP 클라이언트가 프록시 역할을 하는 HTTP 서버를 통해 UDP 통신을 위한 터널을 생성할 수 있게 하는 프로토콜을 정의합니다.

이 메모의 상태

이 문서는 인터넷 표준 트랙 문서입니다.

본 문서는 Internet Engineering Task Force(IETF)의 산물입니다. IETF 커뮤니티의 합의를 반영합니다. 공개 검토를 거쳤으며 Internet Engineering Steering Group(IESG)의 출판 승인을 받았습니다. 인터넷 표준에 관한 추가 정보는 RFC 7841의 섹션 2에서 확인할 수 있습니다.

본 문서의 현재 상태, 정오표 및 이에 대한 피드백 제공 방법에 관한 정보는 https://www.rfc-editor.org/info/rfc9298에서 확인할 수 있습니다.

목차

1. 소개

HTTP가 프록시에 대한 TCP [TCP] 터널을 생성하기 위해 CONNECT 메서드(참조 RFC9110 섹션 9.3.6 of [HTTP])를 제공하는 반면, 본 규격 이전에는 UDP [UDP] 트래픽에 대해 동일한 방식의 메서드가 없었습니다.

본 문서는 HTTP를 통해 UDP 전용 프록시로 동작하는 서버로 UDP를 터널링하기 위한 프로토콜을 설명합니다. UDP 터널은 종단 간 가상 연결을 생성하는 데 흔히 사용되며, 그런 다음 QUIC [QUIC]이나 UDP 위에서 동작하는 다른 프로토콜로 보안을 적용할 수 있습니다. HTTP CONNECT 메서드와 달리, UDP 프록시 자체는 트래픽의 목적지를 포함한 절대 URL로 식별됩니다. 클라이언트는 섹션 2에 설명된 대로 URI 템플릿 [TEMPLATE]을 사용하여 해당 URL을 생성합니다.

이 프로토콜은 HTTP 데이터그램 [HTTP-DGRAM]을 사용하여 모든 기존 HTTP 버전을 지원합니다. HTTP/2 [HTTP/2] 또는 HTTP/3 [HTTP/3]를 사용할 때는 [EXT-CONNECT2][EXT-CONNECT3]에 설명된 대로 HTTP Extended CONNECT를 사용합니다. HTTP/1.x [HTTP/1.1]을 사용할 때는 RFC9110 섹션 7.8 of [HTTP]에 정의된 HTTP Upgrade를 사용합니다.

1.1. 관습 및 정의

본 문서에서의 주요 용어 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", 및 "OPTIONAL"은 모두 대문자로 표시될 때에 한해 BCP 14([RFC2119][RFC8174])에 설명된 대로 해석됩니다.

본 문서에서는 HTTP 서버가 클라이언트의 UDP 터널링 요청을 처리하여 대상 서버에 UDP 소켓을 열고 해당 요청에 대한 응답을 생성하는 역할을 하는 경우를 "UDP 프록시"라고 칭합니다. 클라이언트와 UDP 프록시 사이에 HTTP 중개자(참조 RFC9110 섹션 3.7 of [HTTP])가 존재하는 경우, 본 문서에서는 이를 "중개자"라고 부릅니다.

사용 중인 HTTP 버전이 스트림의 멀티플렉싱을 지원하지 않는 경우(예: HTTP/1.1) 본 문서의 "스트림"이라는 용어는 전체 연결을 나타냅니다.

2. 클라이언트 구성

HTTP 클라이언트는 변수 "target_host" 및 "target_port"를 포함하는 URI 템플릿 [TEMPLATE]로 UDP 프록시를 사용하도록 구성됩니다. 아래에 예시가 나옵니다:

https://example.org/.well-known/masque/udp/{target_host}/{target_port}/
https://proxy.example.org:4443/masque?h={target_host}&p={target_port}
https://proxy.example.org:4443/masque{?target_host,target_port}
그림 1: URI 템플릿 예시

다음 요구사항들이 URI 템플릿에 적용됩니다:

클라이언트는 위 요구사항을 검증하는 것이 권장됩니다(SHOULD); 그러나 특정 검증을 수행하지 못하는 범용 URI 템플릿 구현을 사용할 수 있습니다(MAY). 클라이언트가 URI 템플릿이 위 요구사항을 충족하지 않는 것을 감지하면, 클라이언트는 구성 설정을 거부하고 요청을 UDP 프록시로 전송하지 않고 중단해야 합니다(MUST).

원래의 HTTP CONNECT 메서드는 대상 호스트와 포트를 전달할 수 있었지만 스킴, 프록시 권한, 경로 또는 쿼리는 전달하지 못했습니다. 따라서 프록시 호스트와 포트만 구성하도록 허용하는 프록시 구성 인터페이스를 가진 클라이언트가 존재합니다. 이러한 제약이 있는 구현은 기본 템플릿을 사용해 UDP 프록시 기능에 접근을 시도할 수 있습니다(MAY). 기본 템플릿은 "https://$PROXY_HOST:$PROXY_PORT/.well-known/masque/udp/{target_host}/{target_port}/"로 정의되며, 여기서 $PROXY_HOST와 $PROXY_PORT는 각각 구성된 UDP 프록시의 호스트와 포트입니다. UDP 프록시 배포자는 이러한 클라이언트와 상호운용해야 하는 경우 이 위치에서 서비스를 제공해야 합니다(SHOULD).

3. HTTP를 통한 UDP 터널링

UDP over HTTP 터널 협상을 허용하기 위해, 본 문서는 "connect-udp" HTTP 업그레이드 토큰을 정의합니다. 생성된 UDP 터널은 캡슐 프로토콜(참조 RFC9297 섹션 3.2 of [HTTP-DGRAM])을 사용하고, HTTP 데이터그램은 섹션 5에 정의된 형식을 따릅니다.

단일 HTTP 스트림에 연관된 UDP 터널을 시작하려면, 클라이언트는 "connect-udp" 업그레이드 토큰을 포함한 요청을 전송합니다. 터널의 대상은 클라이언트가 URI 템플릿의 "target_host" 및 "target_port" 변수를 통해 UDP 프록시에 표시합니다; 참조 섹션 2.

"target_host"는 DNS 이름, IPv6 리터럴 및 IPv4 리터럴 사용을 지원합니다. IPv6 범위 지정(zone) 식별자는 지원되지 않음을 주의하세요. [URI]의 IPv6address, IPv4address, reg-name 및 port 용어를 사용하여, "target_host" 및 "target_port" 변수는 MUST 그림 2에 나오는 형식을 따라야 하며, 표기에는 [ABNF]를 사용합니다. 추가로:

target_host = IPv6address / IPv4address / reg-name
target_port = port
그림 2: URI 템플릿 변수 형식

클라이언트는 UDP 프록시 요청을 보낼 때 URI 템플릿 확장을 수행하여 요청의 경로와 쿼리를 결정해야 합니다(SHALL).

요청이 성공하면, UDP 프록시는 터널이 닫힐 때까지 수신된 HTTP 데이터그램을 UDP 패킷으로, UDP 패킷을 HTTP 데이터그램으로 변환하는 작업을 수행할 것을 약속합니다.

캡슐 프로토콜 정의(참조 RFC9297 섹션 3.2 of [HTTP-DGRAM])에 의거하여, UDP 프록시 요청은 어떠한 메시지 본문도 포함하지 않습니다. 마찬가지로 성공적인 UDP 프록시 응답도 메시지 본문을 포함하지 않습니다.

3.1. UDP 프록시 처리

UDP 프록시 요청을 수신하면 다음을 수행합니다:

  • 수신자가 다른 HTTP 프록시를 사용하도록 구성된 경우, 수신자는 요청을 다른 HTTP 서버로 전달하여 중개자로 동작합니다. 이러한 중개자는 요청을 전달할 때 수신에 사용된 HTTP 버전과 다른 버전으로 재인코딩해야 할 수 있음을 유의하세요(아래에서 요청 인코딩이 버전별로 다름).
  • 그렇지 않으면, 수신자는 UDP 프록시로 동작합니다. 수신자는 요청 헤더에서 재구성한 URI에서 "target_host" 및 "target_port" 변수를 추출하고 퍼센트 인코딩을 디코드한 다음 요청된 대상에 직접 UDP 소켓을 열어 터널을 설정합니다.

TCP와 달리 UDP는 비연결형입니다. UDP 소켓을 여는 UDP 프록시는 대상이 도달 가능한지 알 수 없으므로 대상에서 패킷을 기다리지 않고 요청에 응답해야 합니다. 그러나 "target_host"가 DNS 이름인 경우 UDP 프록시는 응답하기 전에 DNS 조회를 수행해야 합니다(MUST). 이 과정에서 오류가 발생하면 UDP 프록시는 요청을 거부해야 하고, 적절한 Proxy-Status 헤더 필드([PROXY-STATUS])를 사용하여 세부 사항을 전송하는 것이 권장됩니다(SHOULD). 예를 들어, DNS 조회 오류가 발생하면 프록시는 RFC9209 섹션 2.3.2의 dns_error 프록시 오류 유형을 사용할 수 있습니다.

운영체제가 지원하는 경우 UDP 프록시는 connected UDP 소켓을 사용할 수 있으며, 이는 커널이 올바른 5-튜플과 일치하는 UDP 패킷만 프록시에게 전달하도록 신뢰할 수 있게 합니다. 비연결형(non-connected) 소켓을 사용하는 경우, UDP 프록시는 수신된 패킷의 IP 출처 주소 및 UDP 출처 포트를 검증하여 클라이언트 요청과 일치하는지 확인해야 합니다(MUST). 일치하지 않는 패킷은 프록시가 폐기해야 합니다(MUST).

소켓의 수명은 요청 스트림에 연결됩니다. UDP 프록시는 요청 스트림이 열려 있는 동안 소켓을 열어 두어야 합니다(MUST). 운영체제로부터 소켓이 더 이상 사용 불가능하다는 통지를 받으면 UDP 프록시는 요청 스트림을 닫아야 합니다(MUST). 예를 들어, ICMP Destination Unreachable 메시지를 수신할 때 발생할 수 있습니다(참조 RFC4443 섹션 3.1 of [ICMP6]). UDP 프록시는 비활성 기간으로 인해 소켓을 닫을 수 있지만(MAY), 소켓을 닫을 때는 요청 스트림을 닫아야 합니다(MUST). 비활성 기간 이후 소켓을 닫는 구현은 2분보다 짧은 기간을 사용해서는 안 됩니다(SHOULD NOT); 참고 RFC4787 섹션 4.3 of [BEHAVE].

성공 응답(섹션 3.33.5에 정의됨)은 UDP 프록시가 요청된 대상에 소켓을 열었고 UDP 페이로드를 프록시할 의향이 있음을 나타냅니다. 성공 응답 이외의 응답은 요청이 실패했음을 의미하므로 클라이언트는 요청을 중단해야 합니다(MUST).

UDP 프록시는 HTTP 데이터그램을 UDP 소켓으로 전달할 때 IP 계층에서 단편화를 도입해서는 안 됩니다; 너무 큰 데이터그램은 조용히 폐기됩니다(MUST NOT). IPv4의 경우 가능한 경우 Don't Fragment(DF) 비트를 설정하여 경로상 단편화를 방지해야 합니다(MUST). 향후 확장이 이러한 요구사항을 제거할 수 있습니다(MAY).

UDP 프록시 구현자는 [UDP-USAGE]의 지침을 참고하면 도움이 됩니다.

3.2. HTTP/1.1 요청

HTTP/1.1 [HTTP/1.1]을 사용할 때, UDP 프록시 요청은 다음 요구사항을 충족해야 합니다:

  • 메서드는 "GET"이어야 합니다(SHALL).
  • 요청은 UDP 프록시의 오리진을 포함하는 단일 Host 헤더 필드를 포함해야 합니다(SHALL).
  • 요청은 값이 "Upgrade"인 Connection 헤더 필드를 포함해야 합니다(이 요구사항은 RFC9110 섹션 7.6.1에 따라 대소문자 구분이 없습니다)(SHALL).
  • 요청은 값이 "connect-udp"인 Upgrade 헤더 필드를 포함해야 합니다(SHALL).

이러한 제한을 충족하지 않는 UDP 프록시 요청은 잘못된 형식입니다. 이러한 잘못된 요청의 수신자는 오류로 응답해야 하며 400 (Bad Request) 상태 코드를 사용하는 것이 권장됩니다(MUSTSHOULD).

예를 들어, 클라이언트가 URI 템플릿 "https://example.org/.well-known/masque/udp/{target_host}/{target_port}/"로 구성되어 있고 대상 192.0.2.6:443에 대한 UDP 프록시 터널을 열려고 하는 경우 다음과 같은 요청을 보낼 수 있습니다:

GET https://example.org/.well-known/masque/udp/192.0.2.6/443/ HTTP/1.1
Host: example.org
Connection: Upgrade
Upgrade: connect-udp
Capsule-Protocol: ?1
그림 3: HTTP/1.1 요청 예시

HTTP/1.1에서는 이 프로토콜이 WebSocket 프로토콜 [WEBSOCKET]의 설계를 모방하기 위해 GET 메서드를 사용합니다.

3.3. HTTP/1.1 응답

UDP 프록시는 다음 요구사항을 충족하는 응답으로 성공을 표시해야 합니다(SHALL):

  • 응답의 HTTP 상태 코드는 101 (Switching Protocols)이어야 합니다(SHALL).
  • 응답은 값이 "Upgrade"인 Connection 헤더 필드를 포함해야 합니다(이 요구사항은 대소문자 구분 없음)(SHALL).
  • 응답은 값이 "connect-udp"인 단일 Upgrade 헤더 필드를 포함해야 합니다(SHALL).
  • 응답은 캡슐 프로토콜을 시작하는 HTTP 응답의 요구사항을 충족해야 합니다(참조 RFC9297 섹션 3.2 of [HTTP-DGRAM])(SHALL).

이러한 요구사항이 충족되지 않으면 클라이언트는 프록시 시도를 실패로 간주하고 연결을 중단해야 합니다(MUST).

예를 들어, UDP 프록시는 다음과 같이 응답할 수 있습니다:

HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: connect-udp
Capsule-Protocol: ?1
그림 4: HTTP/1.1 응답 예시

3.4. HTTP/2 및 HTTP/3 요청

HTTP/2 [HTTP/2] 또는 HTTP/3 [HTTP/3]을 사용할 때, UDP 프록시 요청은 HTTP Extended CONNECT를 사용합니다. 이는 서버가 [EXT-CONNECT2][EXT-CONNECT3]에 명시된 대로 HTTP 설정을 전송해야 하고, 요청이 다음 요구사항을 만족하는 HTTP 의사-헤더 필드를 사용해야 함을 요구합니다.

  • :method 의사-헤더 필드 SHALL 은 "CONNECT"여야 합니다.
  • :protocol 의사-헤더 필드 SHALL 은 "connect-udp"여야 합니다.
  • :authority 의사-헤더 필드 SHALL 은 UDP 프록시의 권한(authority)을 포함해야 합니다.
  • :path 및 :scheme 의사-헤더 필드는 SHALL NOT 비어 있어서는 안 됩니다. 그 값들은 URI 템플릿 확장 과정이 완료된 후의 URI 템플릿에서 온 스킴과 경로를 포함해야 합니다(SHALL).

이러한 제한을 준수하지 않는 UDP 프록시 요청은 잘못된 형식입니다(자세한 내용은 RFC 9113 섹션 8.1.1 of [HTTP/2]RFC 9114 섹션 4.1.2 of [HTTP/3] 참고).

예를 들어, 클라이언트가 URI 템플릿 "https://example.org/.well-known/masque/udp/{target_host}/{target_port}/"로 구성되어 있고 대상 192.0.2.6:443에 대한 UDP 프록시 터널을 열려는 경우, 다음과 같은 요청을 보낼 수 있습니다:

HEADERS
:method = CONNECT
:protocol = connect-udp
:scheme = https
:path = /.well-known/masque/udp/192.0.2.6/443/
:authority = example.org
capsule-protocol = ?1
Figure 5: 예시 HTTP/2 요청

3.5. HTTP/2 및 HTTP/3 응답

UDP 프록시는 다음 요구사항을 충족하는 응답으로 성공을 나타내야 합니다:

  • 응답의 HTTP 상태 코드는 2xx(성공) 범위에 있어야 합니다(SHALL).
  • 응답은 캡슐 프로토콜을 시작하는 HTTP 응답의 요구사항을 충족해야 합니다; 자세한 내용은 RFC 9297 섹션 3.2 of [HTTP-DGRAM]를 참조하십시오(SHALL).

이 요구사항들 중 어느 하나라도 충족되지 않으면, 클라이언트는 이 프록시 시도를 실패로 간주하고 요청을 중단해야 합니다(MUST).

예를 들어, UDP 프록시는 다음과 같이 응답할 수 있습니다:

HEADERS
:status = 200
capsule-protocol = ?1
Figure 6: 예시 HTTP/2 응답

4. 컨텍스트 식별자

본 문서에서 정의한 HTTP에서의 UDP 프록시 메커니즘은 향후 UDP 페이로드와 다른 의미론을 가지는 HTTP 데이터그램을 교환하는 확장을 허용합니다. 이러한 확장 중 일부는 UDP 페이로드에 추가 데이터를 보강할 수 있고, 다른 확장은 UDP 페이로드와 완전히 별개의 데이터를 교환할 수 있습니다. 이를 위해 UDP 프록시 요청 스트림과 연계된 모든 HTTP 데이터그램은 Context ID 필드로 시작합니다; 자세한 내용은 섹션 5를 참조하십시오.

Context ID는 62비트 정수(0 ~ 262-1)입니다. Context ID는 가변 길이 정수로 인코딩됩니다; 참조 RFC 9000 섹션 16 of [QUIC]. Context ID 값 0은 UDP 페이로드용으로 예약되어 있으며, 0이 아닌 값은 동적으로 할당됩니다. 0이 아닌 짝수 Context ID는 클라이언트가 할당하고, 홀수 Context ID는 프록시가 할당합니다. Context ID 네임스페이스는 주어진 HTTP 요청에 묶여 있습니다; 동일한 숫자 값을 가진 Context ID가 서로 다른 요청에서 동시에 할당되어 서로 다른 의미를 가질 수 있습니다. Context ID는 주어진 HTTP 네임스페이스 내에서 재할당되어서는 안 되며(MUST NOT), 임의의 순서로 할당될 수 있습니다(MAY). 짝수/홀수 할당 제한은 엔드포인트 간 동기화 필요를 피하기 위해 존재합니다. 그러나 일단 Context ID가 할당되면, 그 사용에는 원래 할당한 엔드포인트와 무관하게 모든 클라이언트나 UDP 프록시가 사용할 수 있습니다.

등록(Registration)은 엔드포인트가 특정 Context ID의 의미와 형식을 피어에게 알리는 행위입니다. 본 문서는 등록 방식 자체를 정의하지 않습니다. 향후 확장은 Context ID를 등록하기 위해 HTTP 헤더 필드나 캡슐을 사용할 수 있습니다. 사용 중인 방법에 따라, 등록 메시지가 전송되는 패킷과 데이터그램을 포함하는 패킷의 전달 순서가 바뀌어 등록 전에 Context ID가 포함된 데이터그램이 수신될 수 있습니다. 예를 들어 전송 중에 패킷 재정렬로 인해 발생할 수 있습니다.

5. HTTP 데이터그램 페이로드 형식

UDP 프록시 요청 스트림과 연관된 HTTP 데이터그램(참조 RFC 9297 섹션 2 of [HTTP-DGRAM])의 경우, HTTP 데이터그램 페이로드 필드는 그림 7에 정의된 형식을 가집니다. 표기는 RFC 9000 섹션 1.3 of [QUIC]의 표기법을 사용합니다. 참고로 HTTP 데이터그램이 QUIC DATAGRAM 프레임을 사용하여 인코딩될 때에는 Context ID 필드가 QUIC DATAGRAM 프레임 페이로드의 시작에 있는 Quarter Stream ID 필드 바로 다음에 위치합니다; 자세한 내용은 RFC 9297 섹션 2.1 of [HTTP-DGRAM]를 참조하십시오.

UDP Proxying HTTP Datagram Payload {
  Context ID (i),
  UDP Proxying Payload (..),
}
Figure 7: UDP 프록시 HTTP 데이터그램 형식
Context ID:

가변 길이 정수(참조 RFC 9000 섹션 16 of [QUIC])로서 Context ID 값을 포함합니다. 알려지지 않은 Context ID를 가지는 HTTP/3 데이터그램을 수신하면, 수신자는 해당 데이터그램을 묵시적으로 폐기하거나 해당 Context ID의 등록을 기다리며 일시적으로(왕복 지연 정도) 버퍼링해야 합니다(SHALL).

UDP Proxying Payload:

이전 필드의 값에 따라 의미가 결정되는 데이터그램의 페이로드입니다. 이 필드는 비어 있을 수 있습니다.

UDP 패킷은 Context ID 필드가 0으로 설정된 HTTP 데이터그램을 사용하여 인코딩됩니다. Context ID가 0으로 설정된 경우, UDP Proxying Payload 필드는 UDP 패킷의 수정되지 않은 페이로드(UDP에서의 data octets)를 포함합니다(참조 [UDP]).

UDP 헤더의 정의로 인해 UDP 페이로드는 65527 바이트보다 길 수 없습니다. 따라서 엔드포인트는 Context ID가 0인 상태에서 UDP Proxying Payload 필드가 65527보다 긴 HTTP 데이터그램을 전송해서는 안 됩니다(MUST NOT). Context ID가 0인 HTTP 데이터그램을 수신했는데 해당 UDP Proxying Payload 필드가 65527보다 길면, 해당 스트림을 중단해야 합니다(MUST). UDP 프록시가 기본 링크 MTU 때문에 보낼 수 있는 UDP 패킷 길이에 제한이 있는 경우, 그 제한보다 긴 Context ID 0의 HTTP 데이터그램을 수신하면 이를 폐기할 수밖에 없습니다. 폐기된 HTTP 데이터그램이 DATAGRAM 캡슐로 전송되었다면, 수신자는 해당 캡슐의 내용을 버퍼링하지 않고 폐기하는 것이 권장됩니다(SHOULD).

UDP 프록시가 해당 요청을 아직 수신하기 전에 HTTP 데이터그램을 수신하면, 수신자는 그 HTTP 데이터그램을 묵시적으로 폐기하거나 해당 요청을 기다리며 일시적으로(왕복 지연 정도) 버퍼링해야 합니다(SHALL).

데이터그램을 버퍼링하는 것은(요청 미수신 또는 Context ID 미등록 등으로 인해) 자원을 소비합니다. 데이터그램을 버퍼링하는 수신자는 자원 고갈 위험을 줄이기 위해 버퍼링 한도를 적용해야 합니다(SHOULD). 예를 들어, 수신자는 스트림별, 컨텍스트별 또는 연결별로 버퍼링된 데이터그램의 총수 또는 누적 크기를 제한할 수 있습니다.

클라이언트는 UDP 프록시 요청의 응답을 받기 전에 낙관적으로 HTTP 데이터그램으로 UDP 패킷 전송을 시작할 수 있습니다(MAY). 다만 구현자는 프록시가 요청을 실패로 응답하거나 프록시가 요청보다 먼저 받은 프록시 패킷을 버퍼링하지 않도록 선택한 경우 이러한 프록시된 패킷이 처리되지 않을 수 있음을 유의해야 합니다.

6. 성능 고려사항

버스티(bursty) 트래픽은 종종 시간적으로 상관된 패킷 손실을 초래하며, 이는 UDP 위에서 동작하는 프로토콜의 혼잡 제어기가 비최적의 반응을 보이게 할 수 있습니다. 이를 피하기 위해 UDP 프록시는 UDP 트래픽의 버스티니스를 증가시키지 않도록 노력해야 하며(SHOULD), 배치를 늘리기 위해 패킷을 큐잉해서는 안 됩니다(SHOULD NOT).

프록시되는 UDP 위에서 동작하는 프로토콜이 혼잡 제어를 사용하는 경우(예: [QUIC]), 프록시된 트래픽은 적어도 두 개의 중첩된 혼잡 제어를 겪게 됩니다. 기본 HTTP 연결은 내부 트래픽이 혼잡 제어되는지에 대해 오프라인(out-of-band) 방식으로 절대확실히 알 수 있는 방법이 없는 한 혼잡 제어를 비활성화해서는 안 됩니다(MUST NOT).

UDP 프록시 요청 스트림을 포함하는 연결의 클라이언트 또는 UDP 프록시가 혼잡 제어를 비활성화하는 경우, 해당 연결에서 ECN(명시적 혼잡 통지) 지원을 신호해서는 안 됩니다(MUST NOT). 즉, 모든 IP 헤더를 Not-ECT 코드포인트로 표시해야 합니다(MUST). 다만 피어가 혼잡 제어를 비활성화하지 않았을 수 있으므로 QUIC ACK_ECN 프레임이나 TCP ECE 비트를 통해 ECN 피드백 보고는 계속할 수 있습니다(MAY).

프록시되는 UDP 위에서 동작하는 프로토콜이 손실 복구를 사용하는 경우(예: [QUIC]), 그리고 기본 HTTP 연결이 TCP 위에서 실행되는 경우, 프록시된 트래픽은 적어도 두 개의 중첩된 손실 복구 메커니즘을 겪게 됩니다. 이는 때때로 두 메커니즘이 독립적으로 동일한 데이터를 재전송하여 성능을 저하시킬 수 있습니다. 이를 피하기 위해 UDP 프록시는 QUIC DATAGRAM 프레임을 활용할 수 있도록 HTTP/3 위에서 수행되는 것이 권장됩니다(SHOULD).

6.1. MTU 고려사항

QUIC Datagram 확장([QUIC-DGRAM])을 사용하는 HTTP/3를 사용할 때, UDP 페이로드는 QUIC DATAGRAM 프레임에 전송됩니다. 이들은 분할(fragmentation)을 지원하지 않으므로 QUIC 연결 설정과 경로 MTU(PMTU)에 의해 결정되는 특정 길이까지만 페이로드를 담을 수 있습니다. UDP 프록시가 QUIC DATAGRAM 프레임을 사용 중이고 대상에서 받은 UDP 페이로드가 QUIC DATAGRAM 프레임에 맞지 않는다면, UDP 프록시는 그 UDP 페이로드를 DATAGRAM 캡슐로 전송해서는 안 됩니다(SHOULD NOT), 왜냐하면 이는 DPLPMTUD와 같은 방법이 의존하는 종단 간 비신뢰성 특성을 무력화하기 때문입니다([DPLPMTUD]). 이러한 상황에서는 UDP 프록시는 해당 UDP 페이로드를 폐기하고 대상에 ICMP Packet Too Big 메시지를 보내는 것이 바람직합니다(참조 RFC 4443 섹션 3.2 of [ICMP6]).

6.2. ECN 마크의 터널링

UDP 프록시링은 IP-in-IP 터널을 생성하지 않으므로, 내부 및 외부 IP 헤더 사이의 ECN 마크 전달에 관한 [ECN-TUNNEL]의 지침은 적용되지 않습니다. UDP 프록시 터널에는 내부 IP 헤더가 없습니다.

이 명세에서 UDP 프록시 클라이언트는 UDP 프록시가 대상에 보내는 UDP 패킷의 ECN 코드포인트를 제어할 능력이 없고, UDP 프록시가 대상에서 UDP 프록시로 온 각 UDP 패킷의 마킹을 클라이언트에게 전달할 수 없다는 점에 유의하십시오.

UDP 프록시는 대상에서 수신한 UDP 패킷의 IP 헤더에 있는 ECN 비트를 무시해야 하며(MUST), 대상에 보내는 UDP 패킷의 ECN 비트를 Not-ECT로 설정해야 합니다(MUST). 이들은 클라이언트와 UDP 프록시 간에 전송되는 패킷의 ECN 마킹과는 아무 관련이 없습니다.

7. 보안 고려사항

임의의 클라이언트가 임의의 대상에 터널을 설정하도록 허용하는 것은 상당한 위험을 초래합니다. 이는 악의적인 행위자가 트래픽을 전송하고 그 트래픽의 출처를 UDP 프록시에 귀속시키는 것을 허용할 수 있습니다. UDP 프록시를 지원하는 HTTP 서버는 그 사용을 인증된 사용자로 제한해야 합니다.

들어오는 요청의 소스 IP 주소를 기반으로 액세스 제어 검사를 수행하는 소프트웨어 및 네트워크 배포가 존재합니다. 예를 들어, 일부 소프트웨어는 127.0.0.1에서 시작된 경우 인증되지 않은 구성 변경을 허용합니다. 이러한 소프트웨어가 UDP 프록시와 동일한 호스트나 동일한 브로드캐스트 도메인에서 실행될 수 있습니다. 이 경우 프록시된 UDP 트래픽은 UDP 프록시의 소스 IP 주소로 수신됩니다. 만약 이 소스 주소가 액세스 제어에 사용된다면, UDP 프록시 클라이언트는 UDP 프록시를 통해 자신들의 권한을 상승시켜 원래 가질 수 있는 권한을 초과할 수 있습니다. 이는 UDP 프록시가 취약한 대상(예: 프록시 자신의 주소 및 localhost, 링크-로컬, 멀티캐스트 및 브로드캐스트 주소)에 대한 UDP 프록시 요청을 금지하지 않는 한 무단 접근으로 이어질 수 있습니다. UDP 프록시는 그러한 요청을 거부할 때 destination_ip_prohibited Proxy Error Type을 사용할 수 있습니다(참조 RFC 9209 섹션 2.3.5 of [PROXY-STATUS]).

UDP 프록시는 TCP CONNECT 프록시와 유사한 측면이 많아 남용 인프라로서 DoS(서비스 거부) 공격을 가능하게 할 수 있습니다. 둘 다 공격자의 소스 주소를 공격 대상에서 은폐할 수 있습니다. 무상태 볼류메트릭 공격(예: TCP SYN 플러드 또는 UDP 플러드)의 경우, 두 유형의 프록시 모두 트래픽을 대상 호스트로 전달합니다. 상태를 유지하는 볼류메트릭 공격(예: HTTP 플러딩)이 TCP CONNECT 프록시를 통해 전송되는 경우, 프록시는 대상이 TCP SYN-ACK로 데이터 수신 의사를 표시할 때만 데이터를 전송합니다. 경로가 대상 쪽으로 플러딩되면 TCP CONNECT 프록시는 더 이상 대상의 응답을 받지 못하게 되어 데이터 전송을 중지하게 됩니다. UDP는 UDP 프록시와 대상 사이에 공유 상태를 설정하지 않으므로, UDP 프록시는 이러한 상황에서도 대상에 계속 데이터를 보낼 수 있습니다. UDP 프록시는 대상의 응답을 관찰할 때까지 전달할 UDP 패킷 수를 제한할 수 있지만, 이는 프로토콜이 열린 UDP 포트에서 응답을 제공하는 경우 DoS 공격에 대한 제한된 보호만 제공하며, 합법적인 트래픽에 대해서도 문제를 일으킬 수 있습니다.

본 사양에 적용되는 보안 고려사항은 RFC 9297 섹션 4 of [HTTP-DGRAM]에 설명된 내용과 일치합니다. IP 패킷을 UDP를 통해 터널링하는 것이 가능하므로, [TUNNEL-SECURITY]의 지침이 적용될 수 있습니다.

8. IANA 고려사항

8.1. HTTP 업그레이드 토큰

IANA는 "connect-udp"를 <https://www.iana.org/assignments/http-upgrade-tokens>에 유지되는 "HTTP Upgrade Tokens" 레지스트리에 등록했습니다.

Value:

connect-udp

Description:

UDP 페이로드의 프록싱

Expected Version Tokens:

없음

Reference:

RFC 9298

8.2. Well-Known URI

IANA는 "masque"를 <https://www.iana.org/assignments/well-known-uris>에 유지되는 "Well-Known URIs" 레지스트리에 등록했습니다.

URI Suffix:

masque

Change Controller:

IETF

Reference:

RFC 9298

Status:

permanent

Related Information:

"/.well-known/masque/udp/" 경로 접두사로 식별된 모든 리소스를 포함

9. 참고 문헌

9.1. 규범 참고문헌

[ABNF]
Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, DOI 10.17487/RFC2234, , <https://www.rfc-editor.org/info/rfc2234>.
[ECN]
Ramakrishnan, K., Floyd, S., and D. Black, "The Addition of Explicit Congestion Notification (ECN) to IP", RFC 3168, DOI 10.17487/RFC3168, , <https://www.rfc-editor.org/info/rfc3168>.
[EXT-CONNECT2]
McManus, P., "Bootstrapping WebSockets with HTTP/2", RFC 8441, DOI 10.17487/RFC8441, , <https://www.rfc-editor.org/info/rfc8441>.
[EXT-CONNECT3]
Hamilton, R., "Bootstrapping WebSockets with HTTP/3", RFC 9220, DOI 10.17487/RFC9220, , <https://www.rfc-editor.org/info/rfc9220>.
[HTTP]
Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP Semantics", STD 97, RFC 9110, DOI 10.17487/RFC9110, , <https://www.rfc-editor.org/info/rfc9110>.
[HTTP-DGRAM]
Schinazi, D. and L. Pardue, "HTTP Datagrams and the Capsule Protocol", RFC 9297, DOI 10.17487/RFC9297, , <https://www.rfc-editor.org/info/rfc9297>.
[HTTP/1.1]
Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP/1.1", STD 99, RFC 9112, DOI 10.17487/RFC9112, , <https://www.rfc-editor.org/info/rfc9112>.
[HTTP/2]
Thomson, M., Ed. and C. Benfield, Ed., "HTTP/2", RFC 9113, DOI 10.17487/RFC9113, , <https://www.rfc-editor.org/info/rfc9113>.
[HTTP/3]
Bishop, M., Ed., "HTTP/3", RFC 9114, DOI 10.17487/RFC9114, , <https://www.rfc-editor.org/info/rfc9114>.
[PROXY-STATUS]
Nottingham, M. and P. Sikora, "The Proxy-Status HTTP Response Header Field", RFC 9209, DOI 10.17487/RFC9209, , <https://www.rfc-editor.org/info/rfc9209>.
[QUIC]
Iyengar, J., Ed. and M. Thomson, Ed., "QUIC: A UDP-Based Multiplexed and Secure Transport", RFC 9000, DOI 10.17487/RFC9000, , <https://www.rfc-editor.org/info/rfc9000>.
[QUIC-DGRAM]
Pauly, T., Kinnear, E., and D. Schinazi, "An Unreliable Datagram Extension to QUIC", RFC 9221, DOI 10.17487/RFC9221, , <https://www.rfc-editor.org/info/rfc9221>.
[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/info/rfc2119>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/info/rfc8174>.
[TCP]
Eddy, W., Ed., "Transmission Control Protocol (TCP)", STD 7, RFC 9293, DOI 10.17487/RFC9293, , <https://www.rfc-editor.org/info/rfc9293>.
[TEMPLATE]
Gregorio, J., Fielding, R., Hadley, M., Nottingham, M., and D. Orchard, "URI Template", RFC 6570, DOI 10.17487/RFC6570, , <https://www.rfc-editor.org/info/rfc6570>.
[UDP]
Postel, J., "User Datagram Protocol", STD 6, RFC 768, DOI 10.17487/RFC0768, , <https://www.rfc-editor.org/info/rfc768>.
[URI]
Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, DOI 10.17487/RFC3986, , <https://www.rfc-editor.org/info/rfc3986>.

감사의 글

이 문서는 MASQUE 작업그룹의 산물이며, 저자는 모든 MASQUE 기여자들에게 감사를 표합니다. 이 제안은 많은 사람들의 이전 작업에서 직접 또는 간접적으로 영감을 받았으며, 특히 [HELIUM]의 Ben Schwartz, [HiNT]의 Lucas Pardue, 그리고 본 문서의 저자가 작성한 원래 MASQUE 프로토콜 [MASQUE-ORIGINAL]에 특히 감사드립니다.

저자는 HTTP 메서드를 사용하여 UDP를 프록시하도록 제안한 Eric Rescorla에게 감사드립니다. 저자는 또한 이 문서를 개선하는 데 기여한 Mark Nottingham과 Lucas Pardue에게 빚을 지고 있습니다. 본 문서의 확장성 설계는 HTTP 데이터그램 설계팀에서 나왔으며, 해당 팀의 구성원으로는 Alan Frindell, Alex Chernyakhovsky, Ben Schwartz, Eric Rescorla, Lucas Pardue, Marcus Ihlar, Martin Thomson, Mike Bishop, Tommy Pauly, Victor Vasiliev, 그리고 이 문서의 저자가 있습니다.

저자 주소

David Schinazi
Google LLC
1600 Amphitheatre Parkway
Mountain View, CA 94043
United States of America