컴퓨터공부

TCP, UDP 체크섬 계산

achivenKakao 2006. 9. 2. 10:37

IP layer에서도 체크섬 확인은 하지만 상위 레이어인 TCP, UDP에서도 마찬가지로 체크섬 계산을 하게 된다.

IP layer와 다른점은 의사헤더가 추가되어 체크섬 계산을 한다는 것이다.

의사헤더는 아래 그림의 파란색 테두리 부분에 해당하며 총 12바이트 크기를 가진다.

아래 그림은 UDP 기준으로 설명하였으나, TCP도 마찬가지 형태가 된다.

 

<의사헤더 필드>

source IP address : 발신지 주소

destination IP address : 목적지 주소

zero : 0

protocol : IP 헤더의 프로토콜 필드 값

UDP length : UDP 경우 UDP 헤더 및 데이터 크기, TCP 경우 TCP 헤더 및 데이터 크기

 

length 필드에 값을 넣을 때 주의할 점은 UDP 경우는 UDP 헤더에 있는 UDP length를 넣어주면 되지만, TCP 체크섬의 경우 TCP 헤더에는 TCP total length가 없고, TCP header length만 있다. 그렇기 때문에 TCP total length를 계산하고 이 값을 다시 big-endian 으로 변환하여 넣어야 한다.

tcp total length = (ip total lenth) - (ip header length)

 

그리고 UDP 길이가 홀수바이트인 경우 체크섬을 위해 짝수바이트로 만들어야 하기 때문에

0값을 가지는 1byte padding이 필요하다.


 

 

 
 
아래는 소스코드 중 체크섬만 확인하는 부분인데, 정리가 안되어 아주 스파게티를 자랑한다
 bool bCksum = true;
 int ip_len = (ih->ver_ihl & 0x0f) <<2;
 tcp_header* th = (tcp_header*)((char*)ih + ip_len);
 
 pseudo_header ph;
 ph.dest_ip = ih->daddr;
 ph.src_ip = ih->saddr;
 ph.zero = 0;
 ph.proto = ih->proto;
 
 // tcp header에는 total length가 없으므로 직접 구해야한다
 // tcp total length = (ip total lenth) - (ip header length)
 u_short tcp_tot = ntohs(ih->tlen) - ip_len;
 ph.len = htons(tcp_tot); // big endian으로 변환

 int totLen = sizeof(ph) + tcp_tot;
 if(totLen%2 != 0) // 홀수 바이트인 경우 1byte padding
  totLen++;
 char* pChkSumField = new char[totLen];
 ZeroMemory(pChkSumField , totLen);
 memcpy(pChkSumField , &ph, sizeof(ph));          // 의사헤더를 가장 앞에
 memcpy(pChkSumField + sizeof(ph), th, tcp_tot); // 그 다음에 UDP or TCP 헤더와 데이터
 u_short chksum_res = Checksum((u_short*)pChkSumField , totLen);
 if(chksum_res != 0)
 {
  printf("Invalid Value..%d,%x\n", chksum_res, chksum_res);
  bCksum = false;
 }