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;
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으로 변환
// 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++;
totLen++;
char* pChkSumField = new char[totLen];
ZeroMemory(pChkSumField , totLen);
memcpy(pChkSumField , &ph, sizeof(ph)); // 의사헤더를 가장 앞에
memcpy(pChkSumField + sizeof(ph), th, tcp_tot); // 그 다음에 UDP or TCP 헤더와 데이터
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;
}
if(chksum_res != 0)
{
printf("Invalid Value..%d,%x\n", chksum_res, chksum_res);
bCksum = false;
}