2008. 8. 28. 21:42

인터넷에 연결된 IP 주소 찾기

인터넷에 연결된 IP 주소 찾기

호스트에 2개 이상의 랜카드가 설치되어 있거나 하나의 랜카드이어도 여러 개의 IP 를 가지고 있는 경우, 인터넷에 연결된 IP 주소를 찾기는 방법으로 제가 추천하는 방법은 2가지가 있어요.


첫번째, 가장 쉬운 방법으로 아주 유명한 웹사이트에 TCP 연결을 한 후, 연결된 TCP 소켓에서 자신의 IP 주소를 가져오는 것입니다. 일부 FTP 클라이언트 프로그램에서 데이타 소켓의 주소를 처리할 때에 애용되는 방법이죠.


두번째, 오늘 생각해 낸 방법으로 호스트의 랜카드 및 IP 주소 리스트를 검색하여서 인터넷에 연결된 IP 주소를 찾는 방법입니다. 동작 원리를 간단히 설명하면 아래와 같아요.


(1) 호스트에서 사용하는 모든 랜카드를 검색하여 Default GW 주소가 설정된 랜카드를 찾는다.
(2) Default GW 주소가 설정된 랜카드의 모든 IP 주소를 검색하여 Default GW 의 Network 주소와 동일한 IP 주소를 찾는다.
(3) 위에서 찾은 IP 주소를 로컬 IP 주소로 리턴한다.

두번째 방법에 대한 소스코드는 아래와 같아요.


================================= 소스코드 =====================================


#include "stdafx.h"
#include <winsock.h>

#include <ntddndis.h>

#include "iptypes.h"
#include "ipifcons.h"


typedef DWORD (WINAPI *ADDIPADDRESS)( IPAddr, IPMask, DWORD, PULONG, PULONG );
typedef DWORD (WINAPI *DELETEIPADDRESS)( ULONG );
typedef DWORD (WINAPI *GETADAPTERSINFO)( PIP_ADAPTER_INFO, PULONG );

ADDIPADDRESS AddIPAddress = NULL;
DELETEIPADDRESS DeleteIPAddress = NULL;
GETADAPTERSINFO GetAdaptersInfo = NULL;


/** 호스트에서 인터넷에 연결되어 있는 IP 주소를 가져온다. */

void PrintIP2()
{
// 호스트에 연결된 IP 주소 중에서 default gw 와 동일한 네트워크에 존재하는 IP 주소를 찾아낸다.
static HINSTANCE hDll;   // ICMP library handle

 if( hDll == NULL )
{
 hDll = LoadLibrary( "iphlpapi.dll" );
}

 if( hDll )
{
 DWORD dwErr, dwAdapterInfoSize = 0;
 PIP_ADAPTER_INFO pAdapterInfo, pAdapt;
 PIP_ADDR_STRING  pAddrStr;

  if( AddIPAddress == NULL )
 {
  AddIPAddress = (ADDIPADDRESS) GetProcAddress( hDll, "AddIPAddress" );
  if( AddIPAddress == NULL ) goto NORMAL_CASE;
 }

  if( DeleteIPAddress == NULL )
 {
  DeleteIPAddress = (DELETEIPADDRESS) GetProcAddress( hDll, "DeleteIPAddress" );
  if( DeleteIPAddress == NULL ) goto NORMAL_CASE;
 }

  if( GetAdaptersInfo == NULL )
 {
  GetAdaptersInfo = (GETADAPTERSINFO) GetProcAddress( hDll, "GetAdaptersInfo" );
  if( GetAdaptersInfo == NULL ) goto NORMAL_CASE;
 }

  if( ( dwErr = GetAdaptersInfo( NULL, &dwAdapterInfoSize ) ) != 0 )
 {
  if( dwErr != ERROR_BUFFER_OVERFLOW )
  {
   goto NORMAL_CASE;
  }
  // QQQ: ERROR_BUFFER_OVERFLOW 인 경우에는 어떻게 처리하지??
 }

  // Allocate memory from sizing information
 if( ( pAdapterInfo = (PIP_ADAPTER_INFO) GlobalAlloc( GPTR, dwAdapterInfoSize )) == NULL )
 {
  goto NORMAL_CASE;
 }

  // Get actual adapter information
 if( ( dwErr = GetAdaptersInfo( pAdapterInfo, &dwAdapterInfoSize ) ) != 0 )
 {
  goto NORMAL_CASE;
 }

  for( pAdapt = pAdapterInfo; pAdapt; pAdapt = pAdapt->Next )
 {
  switch ( pAdapt->Type )
  {
  case MIB_IF_TYPE_ETHERNET:
   // QQQ: 여러개의 default GW 가 나올 수 있으나, 현재는 첫번째 default GW 만 생각한다.
   if( strlen( pAdapt->GatewayList.IpAddress.String ) > 0 )
   {
    DWORD dwGwIp, dwMask, dwIp, dwGwNetwork, dwNetwork;

     dwGwIp = inet_addr( pAdapt->GatewayList.IpAddress.String );

     //printf( "Gateway address = [%s] ", pAdapt->GatewayList.IpAddress.String );
    //printf( "Gateway mask = [%s] ", pAdapt->GatewayList.IpMask.String );

     for( pAddrStr = &(pAdapt->IpAddressList); pAddrStr; pAddrStr = pAddrStr->Next )
    {
     if( strlen(pAddrStr->IpAddress.String) > 0 )
     {
      dwIp = inet_addr( pAddrStr->IpAddress.String );
      dwMask = inet_addr( pAddrStr->IpMask.String );
      dwNetwork = dwIp & dwMask;
      dwGwNetwork = dwGwIp & dwMask;

       //printf( "IP address = [%s], network = %08x ", pAddrStr->IpAddress.String, dwNetwork );
     
      if( dwGwNetwork == dwNetwork )
      {
       printf( "ip address = %s ", pAddrStr->IpAddress.String );
       break;
      }
     }
    }
   }
   break;
  default:
   break;
  }
 }
}

}


int _tmain(int argc, _TCHAR* argv[])
{
PrintIP2();

 return 0;
}