UDP checksum 계산

 

Summry

본 문서에서는 UDP checksum 을 계산하는 방법을 정리한다.

send me email if you have any questions.


UDP checksum

체크섬(checksum)이란 네트워크를 통해서 전송된 데이터의 값이 변경되었는지(무결성)를 검사하는 값으로, 무결성을 통해서 네트워크를 통해서 수신된 데이터에 오류가 없는지 여부를 확인한다.

UDP Checksum 을 계산하기 위해서는 IP Header 와 UDP header에 있는 일부 정보들을 가져와 IPv4 Pseudo Header 를 만든 후에 계산해 줘야 한다.

그림1
UDP Header

그림2
IP Header

그림3
IPv4 Pseudo Header

IPv4 Pseudo Header

그림4
위 예제에서 IP Header와 UDP Header 그리고 Data(test)를 확인할 수 있고 bad cksum이 발생하고 있음을 확인할 수 있다. 0x8083 이 아닌 0xcc2a 가 올바른 cksum 이라고 packet capture tool 에서 말해주고 있는데 실제로 그런지 확인해보자.

field value
Source IPv4 Address c0ff ff32
Destination IPv4 Address c0ff ff33
Zeroes 00
Protocol 0x11(17)
UDP Length 000c
Source Port a45c
Destination Port 270f
Length 000c
Data 7465 7374

IPv4 Pseudo Header

Length Filed 는 UDP Length 와 같은 값을 넣어준다.

UDP checksum calculate

Checksum 계산방법은 IP Header 의 Checksum 계산 방법과 동일하며 IPv4 Pseudo Header 의 필드를 16-bit word 단위로 모두 더하여 합계를 구한 뒤 발생한 carry bit 를 4bit 만큼 다시 합계에 더해 준 후, bit 반전 시키면(1의보수) checksum 이 된다.
Carry & Overflow

  1. 필드를 word단위로 모두 더한다.
    c0ff+ff32+c0ff+ff32+0011+000c+a45c+270f+000c+7465+7374 = 0x533d0
    
  2. 발생한 carry bit를 가산해준다.
    0x533d0 -> 33d0 + 5 = 33d5
    
  3. 1의 보수 연산을 취해준다.
    0011 0011 1101 0101 = 33d5
    1100 1100 0010 1010 = cc2a
    

위의 과정을 통해 올바른 cksum 을 계산할 수 있다.

udp_cksum_cal.c

아래 코드는 checksum 을 계산하는 c 코드이다.

#include <stdio.h>

int main(){
    unsigned short IPv4_Pseudo_Header[] = {
        // IPv4 Header
        0xc0ff, 0xff32, // c0 ff ff 32 => Source IP Address : 192.255.255.50
        0xc0ff, 0xff33, // c0 ff ff 33 => Destination IP Address : 192.255.255.51
        0x0011,         // Zero(0x00), Protocol(0x11)
        0x000c,         // UDP Length

        // UDP Header
        0xa45c,         // a4 5c => Source Port : 0xa45c = 42076
        0x270f,         // 27 0f => Destination Port : 0x270f = 9999
        0x000c,         // UDP Length
        0x7465, 0x7374  // 74 65 73 74 => "test"
    };

    printf("IPv4 Header Checksum\n");

    // step 1. summation
    int sum = 0;
    for(int i = 0; i < sizeof(IPv4_Pseudo_Header) / 2; i++){
        sum += IPv4_Pseudo_Header[i];
    }

    printf("sum : %#x\n", sum);

    // step 2. bit[:15] + bit[16:19]
    int carry_bit = (sum & 0xF0000) >> 16;
    int result = (sum & 0xFFFF) + carry_bit;

    printf("result : %#x\n", result);

    // step 3. ones' complement
    int checksum = ~result;
    checksum &= 0xFFFF;
    printf("checksum : %#x\n", checksum);

    return 0;
}

Reference

UDP Packet Checksum 계산 방법 - 유나아빠