Summry
본 문서에서는 UDP checksum 을 계산하는 방법을 정리한다.
send me email if you have any questions.
UDP checksum
체크섬(checksum)이란 네트워크를 통해서 전송된 데이터의 값이 변경되었는지(무결성)를 검사하는 값으로, 무결성을 통해서 네트워크를 통해서 수신된 데이터에 오류가 없는지 여부를 확인한다.
UDP Checksum 을 계산하기 위해서는 IP Header 와 UDP header에 있는 일부 정보들을 가져와 IPv4 Pseudo Header 를 만든 후에 계산해 줘야 한다.
UDP Header
IP Header
IPv4 Pseudo Header
IPv4 Pseudo Header
위 예제에서 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
- 필드를 word단위로 모두 더한다.
c0ff+ff32+c0ff+ff32+0011+000c+a45c+270f+000c+7465+7374 = 0x533d0
- 발생한 carry bit를 가산해준다.
0x533d0 -> 33d0 + 5 = 33d5
- 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;
}