포워드 프록시는 TCP 세그먼트 경계를 보존하지 않는다
포워드 프록시 양쪽의 트래픽을 살필 때는 TCP 세그먼테이션, 소켓 읽기, HTTP 프레이밍을 구분해야 합니다.
HTTP 응답이 Squid를 거친 뒤 캡처된 여러 TCP 세그먼트에 나타난다고 가정해 봅시다. 그것은 평범한 TCP 동작일 수 있으며, 응답이 잘못 분할되었다는 증거는 아닙니다.
포워드 프록시에는 보통 두 개의 연결이 있습니다:
client ⇄ TCP connection A ⇄ proxy ⇄ TCP connection B ⇄ origin
각 연결은 고유한 TCP 상태와 시퀀스 번호, 패킷화를 가집니다. 프록시는 한 연결에서 데이터를 읽어 다른 연결로 쓸 수 있으며, 원래 세그먼트 크기를 보존하지 않습니다. 버퍼링, 전송 시점, 혼잡, 경로의 크기 제한 때문에 다른 묶음이 생길 수 있습니다.
분리해서 봐야 할 세 가지 경계
| 경계 | 무엇이 결정하는가 |
|---|---|
| TCP 세그먼트 | 전송 계층과 네트워크 경로 |
| 소켓 읽기 결과 | 사용 가능한 스트림 바이트와 호출자의 버퍼 |
| HTTP 메시지 또는 프레임 | HTTP 프로토콜의 프레이밍 규칙 |
한 번의 읽기에는 헤더의 일부, 헤더 전체와 본문 바이트, 또는 하나 이상의 애플리케이션 계층 경계를 넘는 데이터가 들어갈 수 있습니다. TCP는 ‘HTTP 응답의 끝’을 성공한 읽기의 끝에 붙이지 않습니다.
그래서 HTTP/1.1 파서는 헤더를 모으고 해당 본문 프레이밍 규칙(길이, 전송 코딩, 허용된 연결 종료 등)을 적용합니다. HTTP/2 프레임은 그 자체로 TCP 세그먼트를 가로지를 수 있는 프로토콜 구조이며, 네트워크 패킷의 다른 이름이 아닙니다.
성공한 CONNECT 터널은 터널 안의 바이트 스트림을 보존하지만 여전히 두 개의 TCP 구간을 사용합니다. 프록시가 터널 안의 바이트를 바꾸지 않았더라도 세그먼트 경계는 달라질 수 있습니다.
손상을 조사할 때는 재조립한 애플리케이션 데이터를 비교하십시오. 패킷 개수를 비교하거나 양쪽에서 같은 패킷 길이를 기대하는 것은 TCP가 제공하지 않는 경계 보장을 요구하는 일입니다.