본문 바로가기

IT/WinpcapProgramming

TCP/IP IP 패킷 체크섬(Checksum) C언어로 구현하기

/* 
written by kaspy (kaspyx@gmail.com)
*/ 

네트워크 소켓 프로그래밍에서 TCP 및 IP 등에서는 체크섬(checksum)을 통해서 패킷이 변조됬거나 손상됬는지 검사를 해주는 루틴이 있다.

그래서 패킷을 받으면 이값을 검사한뒤에 만약 계산한데로 맞지 않는다면 패킷을 버린다.


이번 포스팅에서는 TCP/IP 에서 IP 체크섬(Checksum) 함수를 구현하는 내용소개하겠다.


아래는 체크섬을 구하는 함수 코드이다.


  1. u_short ip_sum_calc( u_short len_ip_header, u_short * buff )
  2. {
  3.         u_short word16;
  4.         u_int sum = 0;
  5.         u_short i;
  6.         // make 16 bit words out of every two adjacent 8 bit words in the packet
  7.         // and add them up
  8.         for( i = 0; i < len_ip_header; i = i+2 )
  9.         {
  10.                 word16 = ( ( buff[i]<<8) & 0xFF00 )+( buff[i+1] & 0xFF );
  11.                 sum = sum + (u_int) word16;
  12.         }
  13.         // take only 16 bits out of the 32 bit sum and add up the carries
  14.         while( sum >> 16 )
  15.                 sum = ( sum & 0xFFFF ) + ( sum >> 16 );
  16.         // one's complement the result
  17.         sum = ~sum;
  18.        
  19.         return ((u_short) sum);
  20. }


IP 체크섬(Checksum)

http://www.networksorcery.com/enp/protocol/ip.htm


IP 체크섬은 사이즈가 20바이트라서 구하기 쉬운 편이다. 체크섬(checksum) 필드만 0으로 하고 나머지 정보를 입력한다음에 체크섬을 구하면 된다.



위에 그림은 IP 패킷 데이터 샘플이다.

노랑색 바에서 노랑색 바까지가 IP 패킷에 대한 내용이고 20바이트를 차지하고 있다.

IP에 대한 체크섬(Checksum) 값은 0xa231 이다.


모든 정보를 채워주고 체크섬값을 0으로 세팅한다음에 위에 체크섬 함수를 실행해주면 된다.



  1. #include <stdio.h>
  2. #include <Windows.h>
  3.  
  4. #pragma comment (lib, "ws2_32.lib" )
  5.  
  6. unsigned char data[] = "\x45\x00\x00\x30\x00\x00\x40\x00\x3c\x06\x00\x00\xa5\xf6\x0c\xd7\xa5\xf6\x43\xd3";
  7.  
  8. char *src_ip = "165.246.12.215";
  9. char *dest_ip = "165.246.67.211";
  10.  
  11. struct ip_header
  12. {
  13.         unsigned char ip_header_len:4;
  14.         unsigned char ip_version:4;
  15.         unsigned char ip_tos;
  16.         unsigned short ip_total_length;
  17.         unsigned short ip_id;
  18.         unsigned char ip_frag_offset:5;
  19.         unsigned char ip_more_fragment:1;
  20.         unsigned char ip_dont_fragment:1;
  21.         unsigned char ip_reserved_zero:1;
  22.         unsigned char ip_frag_offset1;
  23.         unsigned char ip_ttl;
  24.         unsigned char ip_protocol;
  25.         unsigned short ip_checksum;
  26.         struct in_addr ip_srcaddr;
  27.         struct in_addr ip_destaddr;
  28. };
  29.  
  30. u_short ip_sum_calc( u_short len_ip_header, u_short * buff )
  31. {
  32.         u_short word16;
  33.         u_int sum = 0;
  34.         u_short i;
  35.         // make 16 bit words out of every two adjacent 8 bit words in the packet
  36.         // and add them up
  37.         for( i = 0; i < len_ip_header; i = i+2 )
  38.         {
  39.                 word16 = ( ( buff[i]<<8) & 0xFF00 )+( buff[i+1] & 0xFF );
  40.                 sum = sum + (u_int) word16;
  41.         }
  42.         // take only 16 bits out of the 32 bit sum and add up the carries
  43.         while( sum >> 16 )
  44.                 sum = ( sum & 0xFFFF ) + ( sum >> 16 );
  45.         // one's complement the result
  46.         sum = ~sum;
  47.        
  48.         return ((u_short) sum);
  49. }
  50.  
  51. void main()
  52. {
  53.     unsigned short chksum;
  54.         u_short ipdata[20];     //checksum을 계산할기위한 버퍼
  55.         ip_header *myih;
  56.         char *ptr;
  57.  
  58.     myih = (ip_header*)malloc(sizeof(myih));
  59.         ptr = (char*)myih;
  60.         printf("\n");
  61.     // IP 패킷에 대한 정보들을 저장한다.
  62.     myih->ip_header_len=0x5;
  63.     myih->ip_version = 0x4;
  64.     myih->ip_tos = 0x0;
  65.     myih->ip_total_length = ntohs(0x30);
  66.     myih->ip_id = htons(0x00);
  67.     myih->ip_frag_offset = 0;
  68.     myih->ip_more_fragment = 0;
  69.     myih->ip_dont_fragment = 1;
  70.     myih->ip_reserved_zero =0;
  71.     myih->ip_frag_offset1 =0;
  72.     myih->ip_ttl = 0x3c;
  73.     myih->ip_protocol = 0x06;
  74.     myih->ip_checksum = 0;
  75.     myih->ip_srcaddr.S_un.S_addr = inet_addr(src_ip);
  76.     myih->ip_destaddr.S_un.S_addr = inet_addr(dest_ip);
  77.     //모든 정보를 세팅하고 체크섬을 구한다.
  78.         int i;
  79.         // 1byte 단위 값을 2바이트 배열에 저장함
  80.         for (= 0; i < 20; i ++) {
  81.                 ipdata[i] = *(unsigned char*)ptr++;
  82.     }
  83.         myih->ip_checksum = ip_sum_calc(20, ipdata);
  84.         printf("checksum = %x\n",myih->ip_checksum);
  85. }



* 관련 링크

* 참고 링크

http://www.netfor2.com/ipsum.htm