概要

プログラムソース内で定義されているIPアドレス範囲(192.168.0.0~192.168.0.254)にpingを実行し、応答があればホスト名及びmacアドレスを取得します。
プログラムはコマンドラインで動作します。(IPv4専用)
表示内容は、応答があったIPアドレスとtimeはパケット送信から受信までの時間(ミリ秒)、TTLはIPパケットの生存時間、macアドレス、ホスト名である。

テスト環境

コンパイラ

Visual C++ 2008/2013 Express 32/64bit マルチバイト/UNICODE

実行環境

Windows XP Professional Service Pack 3 32bit(Virtual Box上の仮想マシーン)
Windows 7 Enterprise Service Pack 1 64bit

プログラムソースの概要

ping1.cpp

_tmain

IcmpCreateFile APIによりハンドルを作成します。
IPアドレスは、for文の中の配列ipで定義しています。(ビックエンディアンで設定)
IcmpSendEcho APIでpingを実行します。引数で送信するデータサイズやタイムアウトなどを指定できます。ここではマクロBUF_SIZEで32byteのデータサイズ及び2000ミリ秒をタイムアウト値としています。
APIが正常値を返した場合、SendARP APIによりIPアドレスからmacアドレスを取得します。
gethostbyaddr APIによりIPアドレスからホスト名を取得します。このAPI実行にはWINSOCKの初期化が必要であるため、WSAStartup APIをあらかじめ実行しておきます。
なぜかこのAPIはUNICODE版がないので、MultiByteToWideChar APIによりUNICODEに変換します。
for文のループから抜けたら、IcmpCloseHandle APIによりハンドルの開放、WSACleanup APIによりWINSOCKの開放を行います。

ソースコード

ping1.cpp

//	指定した範囲のIPアドレスにPINGを実行し、レスポンスがあればマックアドレスとホスト名を表示
//	2014/07/20

#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <icmpapi.h>
#include <locale.h>
#include <tchar.h>

#pragma comment(lib,"iphlpapi.lib")
#pragma comment(lib, "Ws2_32.lib")	//	gethostbyaddr関数に必要

#define BUF_SIZE 32

void _tmain(void){
	_tsetlocale(LC_ALL,_TEXT(""));	//	UNICODE文字を標準出力に正しく表示できるように設定
	HANDLE hIcmp;
	IPAddr ipaddr;

	hIcmp=IcmpCreateFile();
	char cbRequest[BUF_SIZE];	//	送信するデータ
	memset(cbRequest,'a',BUF_SIZE);	//	送信するデータを設定
	DWORD cbReply=sizeof(ICMP_ECHO_REPLY)+BUF_SIZE;
	char* pReply=new char[cbReply];	//	受信するヘッダー + 受信するデータ
	PICMP_ECHO_REPLY p=(PICMP_ECHO_REPLY)pReply;

	WSADATA wsaData;
	int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);	//	WINSOCKを初期化

	unsigned char* ip=(unsigned char*)&ipaddr;
	_tprintf(_TEXT("IPアドレス      time  TTL マックアドレス    ホスト名\n"));

	for(unsigned n=0;n<=254;n++){	//	IPアドレスの検索範囲を設定している
		ip[0]=192;	//	IPアドレス	ビックエンディアンで設定
		ip[1]=168;
		ip[2]=0;
		ip[3]=n;
		_tprintf(_TEXT("%3i.%3i.%3i.%3i\r"),ip[0],ip[1],ip[2],ip[3]);
		// pingを実行
		//                           IPアドレス 送信データ データーサイズ                     タイムアウトms
		DWORD ret=IcmpSendEcho( hIcmp ,ipaddr , cbRequest ,BUF_SIZE , NULL , pReply , cbReply , 2000);
		if(ret){	//	pingが成功した
			unsigned char mac[6];
			struct hostent* hostp;
			ULONG len=sizeof(mac)/sizeof(unsigned char);
			if(SendARP(ipaddr,NULL,mac,&len)==NO_ERROR){	//	IPアドレスからmacアドレスを取得
				hostp=gethostbyaddr((const char*)ip,4,AF_INET);	//	IPアドレスからホスト名を取得
				TCHAR buf[64];
				if(hostp)
#ifdef UNICODE
					//	UNICODEに変換
					MultiByteToWideChar(932,0,hostp->h_name,-1,buf,sizeof(buf)/sizeof(TCHAR));
#else
					_tcscpy_s(buf,sizeof(buf)/sizeof(TCHAR),hostp->h_name);
					
#endif
				else
					buf[0]=_T('\0');
				_tprintf(_TEXT("%3i.%3i.%3i.%3i "),ip[0],ip[1],ip[2],ip[3]);
			_tprintf(_TEXT("%4d %4d %02x:%02x:%02x:%02x:%02x:%02x %s\n"),p->RoundTripTime,p->Options.Ttl,mac[0],mac[1],mac[2],mac[3],mac[4],mac[5],buf);
			}

		}else{	//	pingに失敗した場合
		}
	}
	delete [] pReply;
	IcmpCloseHandle(hIcmp);
	WSACleanup();
}

実行ファイルとソースファイルのダウンロード