요약

  • IPv4는 라우터가 읽고 변경해야 하는 헤더만 보호했습니다. 각 처리 지점은 해당 헤더를 검증하고, TTL을 감소시키거나 허용된 다른 필드를 변경하며, 페이로드나 원래 경로가 온전하다고 주장하지 않으면서 체크섬을 갱신할 수 있었습니다.
  • TCP와 UDP는 전송 계층 바이트와 선별된 IP 정보를 담은 의사 헤더에 대해 동일한 1의 보수 산술을 사용했습니다. 이 더 넓은 범위는 잘못 전달된 패킷을 잡아내는 데 도움이 되었지만, 여전히 일관성 증거일 뿐이지 인증, 소유권, 또는 의도적인 변경자가 값을 재계산하지 않았다는 증명이 아니었습니다.
  • 이 산술에는 0이 두 개 있었습니다. RFC 1141의 빠른 증분 갱신 공식은 IPv4 헤더 전체 재계산이0x0000을 내는 지점에서0xFFFF를 만들어낼 수 있었고, RFC 1624가 이 경계를 바로잡았습니다. 이후 IPv6는 기본 헤더의 체크섬을 제거하면서 상위 계층이 자신이 의존하는 항목에 대한 책임을 지도록 했습니다.

멈춰 설 수 없었던 헤더

IPv4 헤더는 불변의 봉투가 아니었습니다. 발신자가 헤더에 Time to Live 값을 넣으면, 데이터그램을 처리하는 모든 인터넷 모듈이 그 값을 적어도 1씩 줄였습니다. 단편화는 전체 길이, 플래그, 오프셋을 바꿀 수 있었습니다. 프로토콜이 허용하는 경우에는 옵션도 수정될 수 있었습니다. 따라서 라우터는 헤더를 받아 이에 의존한 뒤, 전달 전에 정당하게 그 헤더를 변경했습니다.

RFC 791이 인터넷 헤더 체크섬을 정의한 바로 그 맥락입니다. 이 필드는 헤더의 모든 16비트 워드에 대한 1의 보수 합을 다시 1의 보수로 만든 16비트 값이며, 계산 시 체크섬 필드 자체는 0으로 취급합니다. 명시적으로 “헤더에 한해서만” 적용되는 체크섬입니다. TTL처럼 변경되는 필드가 갱신되면, 그 값은 처리 지점에서 검증되고 재계산됩니다.

이 순서가 중요합니다. 라우터는 발신지가 만든 봉인된 주장을 보존하는 것이 아닙니다. 받은 헤더가 산술적으로 일관적인지 검사하고, 승인된 국소 변경을 가한 뒤, 새 헤더에 대한 새로운 주장을 발행합니다. 이 주장은 처리 경계 사이에서, 하나의 헤더 버전에 대해서만 유효합니다.

RFC 791은 무엇이 없는지도 밝힙니다. IP는 확인 응답도, 재전송도, 데이터 오류 제어도 제공하지 않습니다. 헤더 체크섬이 실패하면 즉시 폐기되지만, IPv4 헤더 체크섬이 통과한다고 해서 페이로드에 대해 아무것도 말해주지 않습니다. 신뢰성은 다른 곳의 몫이었습니다. 이 필드는 인터넷 계층이 데이터그램을 처리하기 위해 필요한 정보를 보호할 뿐, 데이터그램이 의미할 수 있는 모든 것을 보호하지 않습니다.

세 가지 검사, 세 가지 다른 경계

“인터넷 체크섬”을 패킷을 감싸는 하나의 포괄적인 덮개처럼 말하고 싶어지기 쉽습니다. 그러나 초기 명세는 세 개의 경계를 긋고 있습니다.

IPv4는 자신의 헤더를 검사합니다.RFC 768은 UDP의 체크섬이 UDP 헤더와 데이터에 개념적 의사 헤더를 더한 범위를 커버한다고 정의합니다.RFC 793은 TCP의 체크섬이 TCP 헤더와 텍스트에 역시 의사 헤더를 더한 범위를 커버한다고 정의합니다. 산술은 관련되어 있지만, 증거는 서로 교환할 수 없습니다.

이 분리 덕분에, 변경 가능한 인터넷 계층 필드가 모든 홉마다 종단 간 전송 체크섬 변경을 강제하지 않았습니다. TCP나 UDP 바이트가 그대로인 동안 TTL은 줄어들 수 있습니다. 라우터는 IPv4 헤더 체크섬을 갱신하고, 종단은 전송 계층 계산의 책임을 유지합니다. 링크 기술이 프레임을 감싸는 또 다른 오류 검출 필드를 추가할 수 있지만, 그 필드 역시 또 다른 수명과 적용 범위 경계를 가집니다.

이 설계는 유한한 주장들의 스택입니다. 링크 검사는 하나의 프레임이 하나의 인접 관계에서 일관되게 도착했다고 말할 수 있습니다. IPv4 헤더 검사는 현재 네트워크 계층 제어 필드들이 자신들의 16비트 합과 일치한다고 말할 수 있습니다. 전송 검사는 종단에서 보이는 세그먼트와 선별된 주소 지정 정보가 서로 일치한다고 말할 수 있습니다. 동일한 패킷이 세 검사를 모두 통과했다고 해서 어느 것도 더 강해지지는 않습니다.

전송되지 않은 헤더

전송 계층 의사 헤더는 인터넷에서 가장 유용한 가상의 객체 중 하나입니다. UDP는 개념적으로 발신 주소, 수신 주소, 프로토콜, UDP 길이를 자신이 합산하는 재료 앞에 붙입니다. TCP는 발신 주소, 수신 주소, 프로토콜, TCP 길이를 담은 96비트 IPv4 의사 헤더를 사용합니다. 이 바이트들은 계산의 입력이지만, 의사 헤더는 별도의 전송 계층 헤더로 전송되지 않습니다.

그 목적은 정확합니다. RFC 768과 RFC 793은 이것이 잘못 라우팅된 데이터그램이나 세그먼트에 대한 보호를 제공한다고 설명합니다. 서로 다른 발신 또는 수신 주소로 전달된 TCP 세그먼트가, 자신의 TCP 바이트가 온전했다는 이유만으로 대충 유효해져서는 안 됩니다. 이 계산은 전송 재료를 전달이 의존하는 네트워크 계층 종단과 프로토콜 번호에 묶어둡니다.

그러나 “묶는다”는 “인증한다”가 아닙니다. 패킷을 구성할 수 있는 발신자는 체크섬도 구성할 수 있습니다. 커버되는 바이트와 필드를 모두 의도적으로 바꾸는 중개자는 그것을 재계산할 수 있습니다. 의사 헤더는 누가 주소를 통제하는지, 레지스트리 기록이 정확한지, 라우팅 정책이 합법적이었는지, 경로가 가로채기를 피했는지를 증명하지 않습니다. 특정 우연한 불일치를 수신 종단에서 관측 가능하게 만들 뿐입니다.

이 가상의 객체가 가치 있는 이유는 계층 경계를 넘으면서 계층을 합치지 않기 때문입니다. IP는 여전히 데이터그램을 전송하고, TCP와 UDP는 여전히 자신의 검증 결과를 소유합니다. 선별된 IP 정보가 전송 계층 계산에 들어오는 이유는 전송 계층이 그것에 의존하기 때문이지, 전송 프로토콜이 라우팅에 대한 권한을 얻기 때문이 아닙니다.

UDP에는 0이 둘 다 필요했다

1의 보수 산술에는 현대적 직관이 받아들이기 어려운 성질이 있습니다. 0은 두 가지 표현을 가진다는 것입니다. 16개의 0비트는 양의 0,0x0000을 이룹니다. 16개의 1비트는 음의 0,0xFFFF를 이룹니다. 산술적으로는 등가일 수 있지만, 프로토콜 전송선 위에서는 서로 다른 의미를 가질 수 있습니다.

RFC 768은 이 구분을 의도적으로 사용합니다. 계산된 UDP 체크섬이 0이면 발신자는 전체 1을 전송합니다. 모든 비트가 0인 UDP 체크섬 필드는 발신자가 체크섬을 생성하지 않았다는 뜻입니다. 따라서0xFFFF는 검사의 유효한 결과가 될 수 있는 반면,0x0000은 원래 IPv4 UDP 규약에서 검사가 생략되었음을 알릴 수 있습니다.

이 특수 사례는 수신자가 진짜 산술 결과를 검사 거부 신호와 혼동하지 않도록 막아줍니다. 또한 정규 인코딩이 의미론의 일부임을 보여줍니다. 구현체는 프로그래밍 언어가 특정 연산 뒤에 두 값을 등가로 본다는 이유만으로 이 두 표현을 하나로 뭉개서는 안 됩니다.

IPv6는 나중에 이 예외 경로를 좁혔습니다.RFC 8200은 기본적으로 UDP 체크섬을 요구합니다. 계산된 0은 전송선에서0xFFFF로 배치되며, 수신자는 모든 비트가 0인 UDP 체크섬을 폐기해야 합니다. 추가 요건을 받는 특정 UDP 터널 캡슐화에 대한 제한된 예외가 존재하지만, 이는 선택적 검증으로의 일반적 회귀가 아닙니다.

재배치 가능했던 산술

패킷 하나하나에 비용을 충분히 쓸 수 없는 기계들에서 저렴한 검증이 중요했습니다.RFC 1071은 공통된 답을 바꾸지 않으면서 1의 보수 덧셈을 빠르게 만들 수 있는 이유를 설명합니다.

짝수와 홀수 바이트 위치를 지키면 합은 교환법칙과 결합법칙을 따릅니다. 구현체는 버퍼를 그룹으로 나누고, 부분 결과를 더한 뒤 나중에 합칠 수 있습니다. 어느 바이트 순서로든 계산하고 최종 결과를 필요에 따라 뒤집을 수 있습니다. 더 넓은 누적기는 자리올림 접기를 미룰 수 있고, 병렬 경로와 기계별 명령은 반복당 더 많은 작업을 할 수 있습니다. 바이트 수가 홀수일 때는 0 패딩이 계산용 마지막 워드를 완성하지만 전송되지는 않습니다.

이것은 일종의 구현 연방주의였습니다. 프로토콜은 전송선 결과와 커버 범위를 고정했지만, 모든 프로세서에 하나의 루프를 강제하지는 않았습니다. PDP-11, 대형 기계, 이후의 라우터는 상호운용을 유지하면서 각자 다른 국소 능력을 활용할 수 있었습니다.

이 자유는 조건부였습니다. 패리티를 지키지 않은 채 바이트를 재배열하면 워드가 달라집니다. 마지막 홀수 옥텟을 빠뜨리면 입력이 달라집니다. 끝-돌아옴 자리올림을 잘못 다루면 대수가 달라집니다. 최적화는 정확한 공통 결과를 재현할 때만, 그리고 평범한 테스트 트래픽이 거의 도달하지 않는 경우까지 포함해서만 정당했습니다.

헤더 전체 대신 하나의 워드

TTL을 감소시키는 라우터는 어떤 16비트 워드가 바뀌었는지 이미 알고 있습니다. IPv4 헤더 전체를 다시 합산할 수도 있지만, 체크섬의 대수는 더 작은 연산을 허용합니다. 이전 워드의 기여를 빼고, 새 워드의 기여를 더하고, 자리올림을 접는 것입니다.

RFC 1141은 이 운영상의 이점을 구체적으로 만들었습니다. 흔한 TTL 갱신에서 TTL에서 1을 빼는 것은 바이트 위치에 따라 저장된 체크섬에 1의 보수 덧셈으로1또는256을 더하는 것에 해당합니다.RFC 1624는 TTL 변경, 단편화, 경로 지정 변경을 증분 계산의 일상적 용례로 나열합니다.

이 최적화는 비용을 변화량에 비례하게 유지합니다. 라우터는 작은 가변 필드가 하나 바뀌었다고 해서 안정적인 발신·수신 필드를 다시 살펴볼 필요가 없습니다. 덕분에 홉당 무결성 검사를 유지하면서도 모든 전달 결정이 헤더 전체 합산 비용을 지불하지 않아도 되었습니다.

또한 정확성을 하나의 방정식 안으로 옮겼습니다. 전체 재계산에는 명확한 기준 의미가 있습니다. 수정된 헤더를 합산하고 그 결과를 보수하면 됩니다. 증분 계산은 모든 이전 체크섬, 이전 필드, 새 필드 조합에서 정확히 등가여야 합니다. “대체로 같음”은 상호운용성이 아닙니다.

잘못된 0을 건너간 공식

RFC 1141은 RFC 1071에서 물려받은 실용적 표기를 개선했지만, 하나의 경계가 남았습니다. RFC 1624는 이전 표현식이 전체 재계산과 다른 값을 만들 수 있음을 보고합니다. 결과가 0일 때 1의 보수 산술이 보존하지 않는 분배법칙을 암묵적으로 사용했기 때문입니다.

실제 예제는 의도적으로 평범합니다. 16비트 필드가0x5555에서0x3285로 바뀌고, 나머지 헤더 옥텟들의 합은0xCD7A입니다. 수정된 헤더를 재계산하면 저장된 체크섬은0x0000이 됩니다. RFC 1141 방식은0xFFFF를 만듭니다.

IPv4 헤더 체크섬 필드에서 이 둘은 안전하게 교환될 수 없습니다. RFC 1624는 IP 헤더에 적어도 하나의 0이 아닌 필드가 있다고 논증합니다. 0이 아닌 입력들의 1의 보수 덧셈은 음의 0은 만들 수 있어도 양의 0은 만들 수 없으므로, 최종 보수 후 헤더 체크섬에는0x0000이 담길 수 있어도0xFFFF는 정당하게 담길 수 없습니다. 이전 방식은 전체 재계산이 만들 수 없는 표현을 만들어낸 것입니다.

바로잡은 형식은HC' = ~(~HC + ~m + m')이며, 덧셈은 1의 보수 산술로 수행합니다. 이것은 유효하지 않은 분배 단계를 피하고, 변경된 헤더를 재계산하는 것과의 등가성을 복원합니다.

그렇다면 이 버그는 어디서나 실패하지 않은 이유는 무엇일까요? RFC 1624는 두 가지 검증 방식을 언급합니다. RFC 1071을 따르는 수신자는 받은 체크섬을 합에 포함하고 결과를 음의 0과 비교할 수 있습니다. 예제에서는 저장된 0의 어느 표현이든 기대한 최종 합에 도달합니다. 반면 체크섬을 재계산해 그 값을 필드와 직접 비교하는 구현체들은 정규가 아닌 결과를 거부할 수 있었습니다.

제품 테스트가 이 경계를 드러냈고, 시뮬레이션이 수정을 검증하는 데 도움이 되었습니다. 이 사건은 체크섬이 쓸모없었다는 증거가 아닙니다. 공유된 표현은 한 수신자의 관용에 의존할 수 없다는 증거입니다. 생산자는 프로토콜의 기준 계산이 정의하는 값을 발행해야 합니다.

IPv6는 반복되던 주장을 제거했다

RFC 8200의 IPv6 기본 헤더에는 인터넷 계층 체크섬 필드가 없습니다. 고정 헤더는 버전, 트래픽 클래스, 플로우 레이블, 페이로드 길이, 다음 헤더, 홉 제한, 128비트 주소를 담습니다. 이 생략이 패킷 무결성이 완성되었다고 선언한 것은 아닙니다. 인터넷이 계산을 요구하는 위치를 바꾼 것입니다.

IP 주소에 의존하는 상위 계층 프로토콜은 128비트 발신 주소와 최종 수신 주소, 상위 계층 길이, 다음 헤더 값을 담은 IPv6 의사 헤더를 사용합니다. ICMPv6는 이 의사 헤더를 특별히 추가하는데, IPv4와 달리 관련 IPv6 필드가 인터넷 계층 체크섬으로 커버되지 않기 때문입니다. TCP와 UDP는 종단 계산을 유지하고, 링크는 자체 검사를 유지할 수 있습니다.

이 아키텍처적 절충은 분명히 보입니다. IPv4는 하위 및 상위 계층이 인접한 검사를 자주 수행하고 있음에도 모든 라우터가 작은 헤더 주장을 검증하고 갱신하게 했습니다. IPv6는 그 반복되는 기본 헤더 작업을 제거하고, 프로토콜들이 실제로 소비하는 필드를 스스로 보호하도록 남겼습니다. 보호되지 않은 의존성의 손상은 여전히 위험이며, 중복 작업에도 비용이 듭니다.

이것은 약함에서 강함으로의 직선적 진행이 아닙니다. 범위의 수정입니다. 인터넷은 호환성과 종단 커버리지가 요구하는 곳에서 1의 보수 전송 경계를 유지하고, 기본 헤더에서 홉당 경계 하나를 제거하며, UDP에 대한 기본 규칙을 강화했습니다.

출처와 불확실성

RFC 768은 UDP의 커버 범위, 의사 헤더, 두 가지 전송선 0을 정의합니다. RFC 791은 IPv4의 가변적이며 헤더 전용인 검사를 정의합니다. RFC 793은 TCP의 커버 범위를 정의합니다. RFC 1071은 구현 성질을 기록합니다. RFC 1141은 증분 갱신을 설명합니다. RFC 1624는 0 경계의 실패와 수정을 문서화합니다. RFC 8200은 IPv6의 경계와 상위 계층 규칙을 보여줍니다.

이 출처들만으로는 단일 발명자, 하나의 구현 방식, 현재의 오프로드 보급률, 또는 보편적인 벤더 기본값을 확립할 수 없습니다. 검출되지 않은 오류에 대한 수치적 주장도 지지하지 않습니다. 통과한 체크섬은 우연한 무결성과 의도적인 재계산을 구분할 수 없고, 실패한 체크섬도 그 자체로 보호된 재료를 바꾼 링크, 장치 또는 행위자를 특정하지 않습니다.

역사적 사실은 더 좁고 더 오래 지속됩니다. 인터넷은 정확히 어떤 바이트가 공통 계산에 들어가는지, 정확히 누가 그것을 갱신하는지, 정확히 어디서 그 의미가 끝나는지를 규정함으로써 일부 오류를 저렴하게 관측 가능하게 만들었다는 것입니다.