Welcome to SapporoWorks! We create stimulating network programs.
By a demand from user, SapporoWorks evolves.
トップページ| ソフトウエア| シェアウエア登録| セキュリティ情報| 開発情報| ドキュメント|
開発情報 > ICMPのECHO&REPLY


概要

ICMPのECHO&REPLY pingコマンドそのまんまです。
これは、WinSockのバージョンは1.xでも使用可能です。

TTLを1から初めて増やしていくことで、tracerouteも出来ると思います。

サンプルは、時間の計測などをミリミリやってないので、実用するにカスタマイズが必要です。

ソース
 
 //ICMPパケットの生成及び送信
 SOCKET IcmpSocketSend(char *addr,int size,unsigned long ttl,int timeout,int squence,int Id)
 {
     SOCKET sock;
     struct sockaddr_in addr_in;
     unsigned char *p,buf[MAX_PACKET];
 
     //socket 作成
     if(INVALID_SOCKET == (sock = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP))){
         Form1->Memo1->Lines->Add("socket(SOCK_RAW,IPPROTO_ICMP) faild.");
         return -1;
     }
 
     //送信タイムアウトを設定
     if( setsockopt( sock,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout))  == SOCKET_ERROR) {
         Form1->Memo1->Lines->Add("setsockopt(SO_SNDTIMEO) faild.");
         return -1;
     }
 
     //受信タイムアウトを設定
     if(setsockopt( sock,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout)) == SOCKET_ERROR) {
         Form1->Memo1->Lines->Add("setsockopt(SO_RCVTIMEO) faild.");
         return -1;
     }
 
     //TTLを設定
     if (setsockopt(sock, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(ttl)) == SOCKET_ERROR){
         Form1->Memo1->Lines->Add("setsockopt(IP_TTL) faild.");
         return -1;
     }
 
     //struct sockaddr_inを設定
     memset(&addr_in,0,sizeof(addr_in));
     addr_in.sin_addr.s_addr =  inet_addr(Form1->EditAddr->Text.c_str());
     addr_in.sin_family = AF_INET;
 
     //ICMPのデータセット
     memset(buf,0,MAX_PACKET); //0でクリア
     IcmpHeader *icmp_hdr;
     icmp_hdr = (IcmpHeader*)buf;
     icmp_hdr->Type = ICMP_ECHO;//ICMPタイプ ECHO
     icmp_hdr->Code = 0;
     icmp_hdr->CheckSum = 0;
     icmp_hdr->Id = Id;
     icmp_hdr->Squence = squence;
     p = buf + sizeof(IcmpHeader);//データ部はXで埋めておく
     memset(p,'X', size - sizeof(IcmpHeader));
 
     icmp_hdr->CheckSum = CheckSum((unsigned short*)buf,size);//チェックサム計算
 
     //ICMPパケット送信
     if(SOCKET_ERROR == sendto(sock,(const char *)buf,size,0,(struct sockaddr*)&addr_in,sizeof(addr_in))){
         Form1->Memo1->Lines->Add("sendto() faild.");
 	return -1;
     }
     return sock;
 }
 




 //pingスレッド
 unsigned long __stdcall PingThread(void *ArgList)
 {
     SOCKET sock;
     unsigned char *p,buf[MAX_PACKET];
 
     unsigned long ttl=atoi(Form1->EditTtl->Text.c_str());
     int timeout = atoi(Form1->EditTimeOut->Text.c_str());
     int Count = atoi(Form1->EditCount->Text.c_str());
     int size= atoi(Form1->EditSize->Text.c_str())+sizeof(IcmpHeader);
     if( size > MAX_PACKET)
 	size = MAX_PACKET;
 
     Form1->Memo1->Lines->Add("");
     wsprintf(buf,"Pinging [%s] with %d bytes of data:",Form1->EditAddr->Text.c_str(),size);
     Form1->Memo1->Lines->Add((char *)buf);
     Form1->Memo1->Lines->Add("");
 
 
     unsigned int  t, ReturnTime;
     struct sockaddr_in addr_in;
     int ip_hdr_len;
     int addr_in_len = sizeof(addr_in);
 
 
     for(int i=0;iProcessMessages();
 
         //送信開始時間取得(ほんとは、パケット送信ぎりぎりでやったほうがいいと思う)
         t=GetTickCount();
 
         //ICMPパケットの生成及び送信
         if(-1==(sock = IcmpSocketSend(Form1->EditAddr->Text.c_str(),size,ttl,timeout,i,i)))
             goto end;
 
         if(SOCKET_ERROR == recvfrom(sock,(char *)buf,MAX_PACKET,0,(struct sockaddr*)&addr_in,&addr_in_len)){
   
             if (WSAGetLastError() == WSAETIMEDOUT) {//タイムアウト
                 Form1->Memo1->Lines->Add("Request timed out.");
     	        goto next;
     	    }else{
                 Form1->Memo1->Lines->Add("recvfrom() faild.");
 	        goto end;
             }
         }
         //受信時間取得(送信時間との差が往復時間)
         ReturnTime = GetTickCount() - t;
 
         //IPヘッダからICMPヘッダの位置を取得
         IpHeader *ip_hdr;
         IcmpHeader *icmp_hdr;
 
         ip_hdr = (IpHeader *)buf;
         ip_hdr_len = (ip_hdr->Len * 4);
         icmp_hdr = (IcmpHeader*)(buf + ip_hdr_len);
 
         //ICMP TYPE に応じた表示
         switch (icmp_hdr->Type) {
             case ICMP_TTL:
                 Form1->Memo1->Lines->Add("TTL");
                 break;
             case ICMP_UNREACHED:
                 Form1->Memo1->Lines->Add("Distnation Unreacheble.");
 		break;
             case ICMP_REPLY:
                 //一応IDを確認するが、これ必要ないかも知れません
                 if(icmp_hdr->Id == i ){
                     wsprintf(buf,"Reply from %s bytes=%d time=%dms TTL=%d",Form1->EditAddr->Text.c_str(),_sint(ip_hdr->TotalLen)-ip_hdr_len-ETHER_LEN,ReturnTime,ip_hdr->TTL);
                     Form1->Memo1->Lines->Add((char *)buf);
                 }
                 break;
             default:
                 wsprintf(buf,"CMTP TYPE=%d",icmp_hdr->Type);
                 Form1->Memo1->Lines->Add((char *)buf);
                 break;
 
         }
 next:
         //次のICMPを送るには、別のSOCKETを作成する必要がある
         //同じSOCKETを送っても、REPLYは1度しか帰らない
         closesocket( sock );
     }
 end:
     Form1->hThread=NULL;
     Form1->Button1->Caption = "Start";
     return 0;
 }
 
 





サンプル

サンプルプログラム実行画面


ソースファイルのダウンロード 006-src.LZH 6Kbyte 実行ファイルのダウンロード 006-bin.LZH 205Kbyte

開発情報 > ICMPのECHO&REPLY

copyright(c) 1995- SapporoWorks
当サイトはリンクフリーです。リンク時に連絡などは必要有りません。また、どのページにリンクして頂いても構いません。