IPパケットの検証とアルゴリズム


1、アルゴリズムの考え方:
       IP/ICMP/IGMP/TCP/UDPなどのプロトコルの検証とアルゴリズムは同じで、アルゴリズムは以下の通りである.
データを送信する場合、IPパケットのチェックサムを計算するために.次の手順に従うべきです.
(1)IPパケットのチェックサムフィールドを0に設定します.
(2)ヘッダを16ビット単位の数字で構成していると見なし、順次バイナリ逆符号和を行う.
(3)得られた結果をチェックサムフィールドに保存します.
データを受信する場合、パケットのチェックサムを計算するのは比較的簡単で、次のステップに従います.
(1)ヘッダを16ビット単位の数字で構成されていると見なし、順次バイナリ逆符号の合計を行い、チェックサムフィールドを含む.
(2)計算されたチェックサムの結果がゼロに等しいかどうかをチェックする(逆コードは16個の0であるべき).
(3)0に等しい場合、説明は整除され、検証は正しい.そうでなければ、チェックサムはエラーです.プロトコルスタックはこのパケットを破棄します.
いわゆる二進法の逆符号は和を求めて、つまり先にバイナリを行って和を求めて、それから反対をとります.
       IPヘッダの検証と計算のアルゴリズムは以下の通りである.
(1)IPパケットのチェックサムフィールドを0に設定します.
(2)ヘッダを16ビット単位の数字で構成していると見なし、順次バイナリ求和を行う(注意:和を求める時は最高位のビットを保存するべきである.                 足し算は32桁です.
(3)上記加算中に発生したキャリー(最上位のキャリー)を低16ビットに加算する(32ビット加算を行う場合、高16ビットと低16ビットを加算する.                  加算した後、この加算の最上位の位置から生じるキャリーを16桁低い位置に加算します.
(4)上記のものと反をとることは、チェックサムを得ることです.
2、実現例:
       アセンブリ:これはlinuxカーネルコードの中で見つけられます.次はarch/x 86/include/asm/checksum_です.32.hの内容:
/*
 *	This is a version of ip_compute_csum() optimized for IP headers,
 *	which always checksum on 4 octet boundaries.
 *
 *	By Jorge Cwik <[email protected]>, adapted for linux by
 *	Arnt Gulbrandsen.
 */
static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
{
	unsigned int sum;

	asm volatile("movl (%1), %0	;
" "subl $4, %2 ;
" "jbe 2f ;
" "addl 4(%1), %0 ;
" "adcl 8(%1), %0 ;
" "adcl 12(%1), %0;
" "1: adcl 16(%1), %0 ;
" "lea 4(%1), %1 ;
" "decl %2 ;
" "jne 1b ;
" "adcl $0, %0 ;
" "movl %0, %2 ;
" "shrl $16, %0 ;
" "addw %w2, %w0 ;
" "adcl $0, %0 ;
" "notl %0 ;
" "2: ;
" /* Since the input registers which are loaded with iph and ihl are modified, we must also specify them as outputs, or gcc will assume they contain their original values. */ : "=r" (sum), "=r" (iph), "=r" (ihl) : "1" (iph), "2" (ihl) : "memory"); return (__force __sum16)sum; }
 
        C言語:多くのネットワークプロトコルは、以下のコードで検証とアルゴリズムを実行します.
/*      */
USHORT CheckSum(USHORT *buffer, int size)
{
	unsigned long cksum=0;
    while (size > 1) 
    {
        cksum += *buffer++;
        size -= sizeof(USHORT);
    }
    if (size) 
    {
        cksum += *(UCHAR*)buffer;
    }
	/*   16bit         */
    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >>16);
    return (USHORT)(~cksum);
}