• ベストアンサー

TCPヘッダのチェックサム算出方法

TCPヘッダのチェックサム算出方法について 1.算出方法はIPヘッダと一緒か? 2.一緒なら unsigned short CalcCheckSum(unsigned short* lpData, /* (in)チェックサム算出文字列の先頭アドレス */ int iDataLen) /* (in)チェックサム算出文字列長 */ { unsigned long lCheckSum = 0; while(iDataLen > 1) { lCheckSum += *lpData++; iDataLen -= 2; } if(iDataLen) { lCheckSum += *(unsigned char *)lpData; } lCheckSum = (lCheckSum & 0xFFFF) + (lCheckSum >> 16); lCheckSum = (lCheckSum & 0xFFFF) + (lCheckSum >> 16); return ((unsigned short)~lCheckSum); } でまちがいないか? 3.オプションが追加されるときはそこも算出対象になるのか?教えていただけないでしょうか? よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • jun2004
  • ベストアンサー率42% (24/57)
回答No.3

これ参考になりませんか。

参考URL:
http://www.f4.dion.ne.jp/~adem/rfc/rfc793.euc.txt
sakaige32
質問者

お礼

参考になりました! 無事、プロトコルアナライザと同一のチェックサムを算出するプログラムを作ることができました。ありがとうございました。

その他の回答 (2)

  • phoenix343
  • ベストアンサー率15% (296/1946)
回答No.2

チェックサムの計算はRFCで決められています。 以下をキーワードに検索するといいと思います。 RFC1071:Computing the Internet Checksum RFC1141:Incremental Updating of the Internet Checksum RFC1624:Computation of the Internet Checksum via Incremental Update

sakaige32
質問者

お礼

回答ありがとうございます。教えていただいた部分をさがしてみます。

  • jun2004
  • ベストアンサー率42% (24/57)
回答No.1

実際に作った事は無いのですが、手元の本を要約すると、TCPヘッダのチェックサムは、TCPヘッダの前に付く96ビットの擬似ヘッダ(始点、終点アドレス、プロトコル識別子、TCPのセグメント長)とTCPヘッダおよびデータを計算対象に含むとあります。 チェックサムの計算方法は、「1の補数の和」の「1の補数」とあるのでIPと同じみたいです。

sakaige32
質問者

お礼

回答ありがとうございます。 擬似ヘッダ(始点、終点アドレス、プロトコル識別子)は検討がつくのですが、TCPのセグメント長ってIPヘッダの中にあるのでしょうか?

関連するQ&A

  • javaのbyte配列へintなどを埋め込む方法

    javaのbyte配列へintなどを埋め込む方法 java初心者です。データ編集がわからなくて悩んでいます。 下記のコードは"棒読みちゃん"といソフトへのTCPパケットを作成するコードです。 char buf[15]; *((short*)&buf[0]) = 0x0001; *((short*)&buf[2]) = speed; *((short*)&buf[4]) = tone; *((short*)&buf[6]) = volume; *((short*)&buf[8]) = voice; *((char* )&buf[10]) = 2; *((long* )&buf[11]) = len; 同じことをJAVAでしたいのですがわかりません。 (バイト型配列へint,long型を簡単に埋め込む方法がわかりません) よろしくお願いします。 よかったら、こちらもお願いします memcpy(&buf[15],message,strlen(messege)); TCPパケットのようなデータ処理が頻繁にある場合、 このようなコードは、どうしたらいいでしょうか? *((unsigned char* )&buf[15]) = message; CとJAVAになってますが、このような処理を簡単に書けないでしょうか?

    • ベストアンサー
    • Java
  • パケット通信

    C言語初心者です。 H8が乗っているコントローラとシリアル(RS232C)で繋がっている機器間で、 パケットを構成し通信したいのですが、そのパケットの快適な構成方法がわかりません。(コントローラ側のプログラムを作っています) イメージとしては構造体を使用すると快適なのかな?と思うのですが、 よくわかりません。 機器側のパケットは仕様があり、 スタートコード(2)-データ長(1)-データ長チェックサム(1)-データ(n)-データチェックサム(1) のような構成になっています。 ( )はバイト数です。 バイナリデータでの通信です。 データの先頭にコマンドコードがあり、機器の制御をするような感じです。 例えばですが、 typedef struct { unsigned char start[2];----->スタートコード(固定) unsigned char len;---------->データ長(変動) unsigned char len_cs;------->データ長チェックサム(計算) unsigned char data[SIZE];--->データの中身(変動) unsigned char data_cs;------>データチェックサム(計算) } packet; というようなやり方で、固定データや変動するデータを構造体として 使用することはできるのでしょうか? unsigned char cmd[] = {0x00,0x00,・・・・0x00} のように強引にスタートコードからデータ、チェックサムを 配列で並べて送信すると機器はちゃんと動作します。 (チェックサムの計算も電卓で計算してから書いてます) ただ、コマンドごとにこんなパケットを構成しないといけない のは手間ですし、何かブサイクに思えます。 快適なパケット作成の方法があればぜひ教えて下さい。 よろしくお願いします。

  • CRC16コード作成プログラムについて

    お世話なります。 PCと対象機械との通信を行おうと思っております。 内容としてCRC16のコードを使って、日時設定をPC→対象機器へ行いたいです。 CRC16の生成プログラムをいろいろ調べてみたところ、 今、自分のスキルでなんとかわかりそうなCRC16のソースが次の通りでした。 (行列の計算ぐらいならC言語で作れる程度です。。。) unsigned short crc_cal(unsigned short lng, unsigned char *str) { unsigned short crc, i, j, t; crc = 0xffff; for (i = 0; i < lng ; i++) { crc ^= (unsigned short) str[i]; for (j = 1; j <= 8; j++) { if (crc & 1) { // carry bit on crc = crc >> 1; crc ^= 0xa001; } else { // carry bit off crc = crc >> 1; } } } return crc; } “0C0C0C0C0C0C”と入力したら、CRCコードが算出されるプログラムを作りたく、 入力部分を作成してみたのですが・・・ int main(void) { unsigned short i,j, t; unsigned char str[256]; unsigned char str0; unsigned short crc; int k=0; printf("Please input key (HEX)\n"); for(k=0; k < 256; k++) { scanf("%c",&str0); // 文字列標準入力 if( str0=='\n') // Enterが押されたときの実行 { str[k]='\0'; // 文末にNULL文字 break; // for文のループ終了 } else { str[k]=str0; // NULLでなければ入力された文字を代入 } } crc = crc_cal(k,str); printf("crc=%X\n", crc); return 0; } 文字列を分解して・・・やるんだろうなってまではなんとなくわかるのですが、 どのようにしたらよいでしょうか。。。 ご教授よろしくお願いします。

  • TCPヘッダのチェックサムについて

    通信エラーが発生し、 エラーが発生した時のパケットのTCPヘッダの チェックサムが"FFFF"だったのですが チェックサムで"FFFF"はありえるのでしょうか?

  • 共用体のアドレスを取得したい

    SH7047のプログラムです。 何をしたいのかと言うと、P_PORTD.PDDRL.BIT.PD4DR等を関数の中で変化させたいのです。 うまく行かない理由はおそらく「P_PORTD.PDDRL.BIT.PD4DRのアドレスは渡すことが出来ない」だとおもいます。 まぁそれも当然な話だと思うのですが、どうにかならないでしょうか? 個人的には「unsigned short* port」→「bit* port」の様に出来れば理想的なのですが。 何か良い方法を教えてください。よろしくお願いします。 #define P_PORTD (*(volatile struct st_portd *)0xFFFF83A2)/* PORTD Address */ struct st_portd { /* struct PORTD */ union { /* PDDRL */ unsigned short WORD; /* Word Access */ struct { /* Bit Access */ unsigned short :7; /* */ unsigned short PD8DR:1; /* PD8DR */ unsigned short PD7DR:1; /* PD7DR */ unsigned short PD6DR:1; /* PD6DR */ unsigned short PD5DR:1; /* PD5DR */ unsigned short PD4DR:1; /* PD4DR */ unsigned short PD3DR:1; /* PD3DR */ unsigned short PD2DR:1; /* PD2DR */ unsigned short PD1DR:1; /* PD1DR */ unsigned short PD0DR:1; /* PD0DR */ } BIT; /* */ } PDDRL; /* */ }; /* */ void main(void) { output(&P_PORTD.PDDRL.BIT.PD4DR,0xff); output(&P_PORTD.PDDRL.BIT.PD5DR,0xff); output(&P_PORTE.PEDRL.BIT.PE12DR,0xff); } void output(unsigned short* port,int data) { P_PORTE.PEIORL.WORD = 0x3fff; P_PORTE.PEDRL.WORD = data & 0xff; *port = 1; *port = 0; P_PORTE.PEIORL.WORD = 0x3f00; }

  • UNIXでのTCP/IP

    クライアントとサーバの通信をするプログラムを作っているのですが gethostbyaddr()でホスト名を得てそれをprintf()からホスト名を表示させたいのです。 //サーバ側 #define MAXPENDING 5 void DieWithError(char *errorMessage); void HandleTCPClient(int clntSocket); char * ResolveAddr(unsigned long addr) { struct hostent *host; host = gethostbyaddr((char *)&addr, sizeof(addr),AF_INET); if (host == NULL) { fprintf(stderr, "gethostbyaddr() failed"); exit(1); } return host->h_name; } int main(int argc, char *argv[]) { int servSock; int clntSock; struct hostent *host; struct sockaddr_in echoServAddr; struct sockaddr_in echoClntAddr; unsigned short echoServPort; unsigned int clntLen; if(argc != 2) { fprintf(stderr, "Usage: %s <Server Port>\n", argv[0]); exit(1); } echoServPort = atoi(argv[1]); if((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))<0) DieWithError("socket() failed"); memset(&echoServAddr, 0, sizeof(echoServAddr)); echoServAddr.sin_family = AF_INET; echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); echoServAddr.sin_port = htons(echoServPort); if(bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr))<0) DieWithError("bind() failed"); if(listen(servSock, MAXPENDING)<0) DieWithError("listen() failed"); for (;;) { clntLen = sizeof(echoClntAddr); if((clntSock = accept(servSock, (struct sockaddr *) &echoClntAddr,&clntLen))<0) DieWithError("accept() failed"); ResolveAddr(echoClntAddr.sin_addr.s_addr); printf("Handling client %s\n", host->h_name); HandleTCPClient(clntSock); } } コンパイルするとクライアントからIPアドレスを渡した際にセグメンテーション違反になるのですがどこが間違っているのか分かりません。

  • コンパイルエラー invalid operands to binary

    自己啓発で入力文字列をBASE64デコードする関数を作っているのですが、L20~L23(a[0] = strchr(b64, p[0]) - b64;)でコンパイルエラーinvalid operands to binaryが発生して色々試行錯誤しているのですが、どうしてもエラーがとれません。 ソースをここに書くのは大変恐縮なのですが、原因がわかる方がいらっしゃいましたら、教えていただけないでしょうか? char *Base64n(unsigned char *buf, size_t length, size_t *outlen) { const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrst         uvwxyz0123456789+/="; unsigned char *p; unsigned char *q; unsigned char a[4]; char *RtnBuf; int j=0; int cnt; RtnBuf = (char *)malloc(length+1); memset(RtnBuf, 0, length+1); p = (unsigned char*)buf; q = (unsigned char*)RtnBuf; cnt = 0; while(*p != 0) { a[0] = a[1] = a[2] = a[3] = 0; a[0] = strchr(b64, p[0]) - b64; a[1] = strchr(b64, p[1]) - b64; a[2] = strchr(b64, p[2]) - b64; a[3] = strchr(b64, p[3]) - b64; q[0] = ((a[0] << 2) | (a[1] >> 4)) & 0xff; cnt++; if (p[2] != '=') { q[1] = ((a[1] << 4) | (a[2] >> 2)) &0xff; cnt++; } if (p[3] != '=') { q[2] = ((a[2] << 6) | a[3]) & 0xff; cnt++; } p += 4; q += 3; } *outlen = cnt; return(RtnBuf); } コンパイルはRed Hatでgccを使ってコンパイルしています。 引数は第1引数がデコード対象の文字列、第2引数がデコード対象文字列長、第3引数がデコード後の文字列長で、戻り値がデコード後の文字列です。

  • WNetAddConnection2で困っています

    お世話になります。 VC6.0のサービス内でのネットワーク接続関数:WNetAddConnection2で困っています。 パラメータ NETRESOURCE nr;の // ローカルドライブ名 nr.lpLocalName = ""; // 共有フォルダ名 nr.lpRemoteName = "\\\\saver\\c$"; がエラーになります 「2 番目の引数を 'char [6]' から 'const unsigned short *' に変換できません。 (新しい機能 ; ヘルプを参照)指示された型は関連がありません; 変換にはreinterpret_cast、 C スタイル キャストまたは関数スタイルのキャストが必要です。」 (unsign short *)のセット方法は下記のように直したのですが // 資源の種類 nr.dwType = RESOURCETYPE_DISK; // ローカルドライブ名 nr.lpLocalName = (unsigned short*)""; // 共有フォルダ名 nr.lpRemoteName = (unsigned short*)"\\\\saver\\c$"; // プロバイダー名 nr.lpProvider = NULL; ・・・ dwret = WNetAddConnection2( &nr,(const unsigned short *)"passdw",(const unsigned short *)"userid",0); コンパイルはとおったのですが 接続できません (unsign short *)のセット方法が悪いのか サービスでなければうまく動くのですが・・・。 サービスなのでデバックもよくできません アドバイス、回答、お願いします。

  • C言語のキャストについて

    お世話になります。 CRC-16の計算プログラムをC言語でつくりました。 例えば・・・1F 08 00 00 12 34 なら“1F0800001234”と入力すると【EEC2】と表示するプログラムです。 ただ・・・.Net SDKでコンパイルするとできたのですが、Visual C++2008でコンパイルするとエラーが出てしまいます。 (48) : error C2664: 'strlen' : 1 番目の引数を 'unsigned char [256]' から 'const char *' に変換できません。(新しい機能 ; ヘルプを参照) 1> 指示された型は関連がありません。変換には reinterpret_cast、C スタイル キャストまたは関数スタイルのキャストが必要です。 (52) : error C2664: 'strtol' : 1 番目の引数を 'unsigned char [3]' から 'const char *' に変換できません。(新しい機能 ; ヘルプを参照) 1> 指示された型は関連がありません。変換には reinterpret_cast、C スタイル キャストまたは関数スタイルのキャストが必要です。 型変換が必要ってことまではわかったのですが・・・必要なのはわかって行き詰まり状態です。。。 どのようしたらよいのでしょうか?ご教授をよろしくお願いします。 ソースは以下の通りです。 #include "stdafx.h" #include <stdio.h> #include <string.h> #include <stdlib.h> unsigned short crc_cal(unsigned short lng, unsigned char *str) { unsigned short crc, i, j, t; t= 0x0000; crc = 0xffff; for (i = 0; i < lng ; i++) { crc ^= (unsigned short) str[i]; t = (unsigned short) str[i]; for (j = 1; j <= 8; j++) { if (crc & 1) { // carry bit on crc = crc >> 1; crc ^= 0xa001; } else { // carry bit off crc = crc >> 1; } } } return crc; } int main(void) { unsigned char str[256],data[128],hexstr[3]; unsigned short crc,CRC,len; while(1) { printf("Please input key (HEX)\n"); scanf("%255s",str); hexstr[2]='\0'; for(len=0; len<(strlen(str)/2) ;len++) { hexstr[0]=str[len*2]; hexstr[1]=str[len*2+1]; data[len]=(unsigned char)strtol(hexstr, NULL, 16); } crc = crc_cal(len,data); CRC = (crc>>8) | (crc<<8); printf("\nCRC16 = %04X\n\n", CRC); } return 0; }

  • freadでダンプ なぜ?

    ファイルを1バイトづつfreadで読み込んで ダンプしているのですが、なぜか16進数で"1A" (10進数で"26")の文字から先をダンプできません。 原因が良くわかりません。 どなたか、わかる方お助けください。  char buf[20];  unsigned short a;  flag = 1;  while (flag == 1){   fread(buf, sizeof(char), 1, fp_in);   a = buf[0];   printf("%02x ",a);   cnt++;   if(cnt == 16){    printf("\n");    cnt = 0;   }     :     : }

専門家に質問してみよう