概要

プログラムソース内で定義されているIPアドレス範囲(192.168.0.0~192.168.0.254)にpingを実行し、応答があればホスト名及びmacアドレスを取得します。
プログラムはコマンドラインで動作します。(IPv4専用)
表示内容は、応答があったIPアドレスとtimeはパケット送信から受信までの時間(ミリ秒)、TTLはIPパケットの生存時間、macアドレス、ホスト名、ベンダー名である。
ベンダー名の一覧は、IEEE-SAのホームページの下のほうのDownload a copyより本プログラムが自動的に取得し、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

プログラムソースの概要

ping2.cpp

_tmain

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

get_mac_vendor

ファイルよりmacアドレスとベンダー名の対応を一覧を作成します。
一覧はvendor_vecに保存されます。

mac2vendor_name

macアドレスよりベンダー名を取得します。該当するmacアドレスがない場合は文字列errorを返します。

ソースコード

ping2.cpp

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

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

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

#define BUF_SIZE 32


struct VENDOR_ID{
        unsigned char mac[3];   //      macアドレス 上位3byte
        TCHAR* name;                    //      ベンダー名
        void put(FILE* fp){
                _ftprintf(fp,_TEXT("%02x:%02x:%02x\t%s\n"),mac[0],mac[1],mac[2],name);
        }
        bool cmp(unsigned char* src_mac){
                if(mac[0]==src_mac[0] && mac[1]==src_mac[1] && mac[2]==src_mac[2])
                        return true;
                else
                        return false;
        }
};

using namespace std;

vector<VENDOR_ID> vendor_vec;     //      macアドレスとベンダー名の一覧

//      macアドレスよりベンダー名を取得する
TCHAR* mac2vendor_name(unsigned char* src_mac);

//      macアドレスとベンダー名の対応を一覧する
void vendor_fput(FILE* fp);

//      macアドレスとベンダー名の対応を一覧する
void vendor_fput(FILE* fp);

//      ファイルよりmacアドレスとベンダー名の対応を一覧を作成する
void get_mac_vendor(FILE* fp);


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


        FILE* fp;
        //      ファイルが開けない場合、インターネットから取得しファイルに保存後、再度ファイルを開く
        if(_tfopen_s(&fp,_TEXT("oui.txt"),_TEXT("r"))){
                _tprintf(_TEXT("ファイルが開けないのでインターネットから取得します\nhttp://standards.ieee.org/develop/regauth/oui/oui.txt\n"));
                if(_tfopen_s(&fp,_TEXT("oui.txt"),_TEXT("wb"))){
                        _tprintf(_TEXT("ファイルが開けません。\n"));
                        return;
                }
                HINTERNET hInet, hUrl;
                //インターネット(WinInet)開始
                hInet = InternetOpen(_TEXT("xyz-123"),
                        INTERNET_OPEN_TYPE_PRECONFIG,   
                        NULL, NULL, 0);
                if (hInet == NULL) {
                        _tprintf(_TEXT("インタネットから取得できませんでした。\n"));
                        return;
                }

                //HTTPセッションの開始, 指定のURLオープン
                hUrl = InternetOpenUrl(hInet, _TEXT("http://standards.ieee.org/develop/regauth/oui/oui.txt"), NULL, 0, 0, 0);
                if (hUrl == NULL) {
                        _tprintf(_TEXT("インタネットから取得できませんでした。\n"));
                        InternetCloseHandle(hInet);
                        return;
                }
                char szBuf[1024];
                DWORD dwRead = 0;
                //読み出す物がなくなるまで読み出す
                while (1) {
                        InternetReadFile(hUrl, szBuf, (DWORD)sizeof(szBuf), &dwRead); 

                        //読み出す物がなくなったのでループ脱出
                        if (dwRead == 0)
                                break;

                        fwrite(szBuf,1,dwRead,fp);
                }
                fclose(fp);

                if(_tfopen_s(&fp,_TEXT("oui.txt"),_TEXT("r"))){
                        _tprintf(_TEXT("ファイルが開けません。\n"));
                        return;
                }
                //インターネットハンドルの解放
                InternetCloseHandle(hUrl);
                InternetCloseHandle(hInet);

        }
        get_mac_vendor(fp);
        fclose(fp);

#ifdef _DEBUG
        if(_tfopen_s(&fp,_TEXT("vendor.txt"),_TEXT("w"))){
                _tprintf(_TEXT("ファイルが開けません。\n"));
                return;
        }
        vendor_fput(fp);
        fclose(fp);
        
#endif

        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 マックアドレス    ベンダー名\tホスト名\n"));

        for(unsigned n=0;n<=244;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\t%s\n"),p->RoundTripTime,p->Options.Ttl,mac[0],mac[1],mac[2],mac[3],mac[4],mac[5],mac2vendor_name(mac),buf);
                        }

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

//      macアドレスよりベンダー名を取得する

TCHAR* mac2vendor_name(unsigned char* src_mac){
        for(unsigned n=0;n<vendor_vec.size();n++){
                if(vendor_vec[n].cmp(src_mac)==true)
                        return vendor_vec[n].name;
        }
        return _TEXT("error");
}

//      macアドレスとベンダー名の対応を一覧する

void vendor_fput(FILE* fp){
        for(unsigned n=0;n<vendor_vec.size();n++){
                vendor_vec[n].put(fp);
        }
}


//      ファイルよりmacアドレスとベンダー名の対応を一覧を作成する

void get_mac_vendor(FILE* fp){
        TCHAR buf[256];
        int f=1;
        int len;
        TCHAR* top;
        TCHAR* p;

        VENDOR_ID id;
        while(_fgetts(buf,sizeof(buf)/sizeof(TCHAR),fp)){
                top=buf;
                while(*top){
                        if(*top!=_T(' '))
                                break;
                        ++top;
                }

                if(f==1){
                        len=(int)_tcslen(top);
                        if(10<=len){
                                if(_istxdigit(top[0]) && top[2]==_T('-')){
                                        f=2;
                                }
                        }

                }
                switch(f){
                        case 2:{
                                TCHAR* name=top;
                                id.mac[0]=(unsigned char)_tcstol(top,NULL,16);
                                id.mac[1]=(unsigned char)_tcstol(top+3,NULL,16);
                                id.mac[2]=(unsigned char)_tcstol(top+6,NULL,16);

                                while(*name){
                                        if(*name==_T(' '))
                                                break;
                                        ++name;
                                }
                                while(*name){
                                        if(*name!=_T(' '))
                                                break;
                                        ++name;
                                }
                                while(*name){
                                        if(*name==_T(')'))
                                                break;
                                        ++name;
                                }
                                while(*name){
                                        if(*name!=_T('\t'))
                                                break;
                                        ++name;
                                }
                                name+=3;
                                p=name;
                                while(*p){
                                        if(*p==_T('\n') || *p==_T('\r') || *p==_T('\t'))
                                                *p=_T('\0');
                                        ++p;
                                }
                                id.name=_tcsdup(name);
                                vendor_vec.push_back(id);
                                f=1;
                                break;
                        }
                }

        }
}

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