카테고리 없음

[네트웍/인터넷] Network Adaptor 가 여러개인 경우의 IP 구하기

정보모음1 2023. 9. 8. 08:59
반응형
// I have need to access the IP address on Win95/WinNT
// where we have TCP/IP on the network card, and also
// on a dial-up connection.
//
// The NM* internet controls have a property 'LocalIP',
// but this returns the address of the NIC, not the dial-up.
//
// How do I get the other IP address, or better still, how
// would I loop through all adaptors ?

// 테스트 결과 Windows NT 에서만 정확히 작동했음(ws2_32.dll 의 버전은 4.00 이었음)
// Windows 95(ws2_32.dll 의 버전은 4.10.1656 이었음) 는 정확히 동작 안함
// longword 형이 없어서 longint 로 대체하여 컴파일 해보았음

unit NetCardsUnit;

interface

uses Windows, Classes, WinSock;

const
  MAX_PROTOCOL_CHAIN  = 7;
  WSAPROTOCOL_LEN     = 255;
  SIO_GET_INTERFACE_LIST = IOC_OUT or
                           ((longint(sizeOf(longint)) and IOCPARM_MASK) shl 16) or
                           (longint(byte('t')) shl 8) or 127;

type
  PINTERFACE_INFO = ^TINTERFACE_INFO;
  TINTERFACE_INFO = packed record
    iiFlags: longint;
    iiAddress: TSockAddrIn;
    iiBroadcastAddress: TSockAddrIn;
    iiNetmask: TSockAddrIn;
  end;

  TGroup            = integer;
  PGroup            = ^TGroup;
  LPWSAOVERLAPPED   = POverlapped;

  PWSAPROTOCOLCHAIN = ^TWSAPROTOCOLCHAIN;
  TWSAPROTOCOLCHAIN = packed record
    ChainLen: integer;  { the length of the chain,     }
                        { length = 0 means layered protocol, }
                        { length = 1 means base protocol,}
                        { length > 1 means protocol chain}
    ChainEntries : array[0..MAX_PROTOCOL_CHAIN-1] of Longword; { a list of dwCatalogEntryIds }
  end;

  PWSAPROTOCOL_INFOA = ^TWSAPROTOCOL_INFOA;
  TWSAPROTOCOL_INFOA = packed record
    dwServiceFlags1      : longword;
    dwServiceFlags2      : longword;
    dwServiceFlags3      : longword;
    dwServiceFlags4      : longword;
    dwProviderFlags      : longword;
    ProviderId           : TGUID;
    dwCatalogEntryId     : longword;
    ProtocolChain        : TWSAPROTOCOLCHAIN;
    iVersion             : integer;
    iAddressFamily       : integer;
    iMaxSockAddr         : integer;
    iMinSockAddr         : integer;
    iSocketType          : integer;
    iProtocol            : integer;
    iProtocolMaxOffset   : integer;
    iNetworkByteOrder    : integer;
    iSecurityScheme      : integer;
    dwMessageSize        : longword;
    dwProviderReserved   : longword;
    szProtocol           : array [0..WSAPROTOCOL_LEN+1-1] of char;
  end;

  PWSAOVERLAPPED_COMPLETION_ROUTINE = procedure(dwError:longword;
                                                cbTransferred:longword; lpOverlapped:LPWSAOVERLAPPED;
                                                dwFlags:longword); stdcall;

  function WSASocket(af:integer; atype:integer; protocol:integer;
                     lpProtocolInfo:PWSAPROTOCOL_INFOA; g:TGroup; dwFlags:longword):TSocket; stdcall;

  function WSAIoctl(s:TSocket; dwIoControlCode:longword; lpvInBuffer:Pointer;
                    cbInBuffer:longword; lpvOutBuffer:Pointer; cbOutBuffer:longword;
                    lpcbBytesReturned:Plongword; lpOverlapped:LPWSAOVERLAPPED;
                    lpCompletionRoutine:PWSAOVERLAPPED_COMPLETION_ROUTINE):integer; stdcall;

type
  TNetCardData = class
    private
    public
      socket: TSocket;
      numInterfaceCards: integer;
      ipAddress: array [1..21] of string;
      interfaceList: array [0..20] of TINTERFACE_INFO;
      constructor Create;
      function GetNumOfInterfaces: integer;virtual;
  end;

implementation

const
  winsocket = 'ws2_32.dll';

  function WSASocket;    external     winsocket name 'WSASocketA';
  function WSAIoctl;     external     winsocket name 'WSAIoctl';

constructor TNetCardData.Create;
var
  wsadata: TWSAData;
  err,i,reOrder: integer;
begin
  numInterfaceCards:=-1;
  try
    err := WSAStartup($202,wsadata);
    if (err = 0) then
    begin
      numInterfaceCards := GetNumOfInterfaces;    // this really gets all of the data
      if numInterfaceCards <> -1 then
      begin
        reOrder := 1;
        for i := numInterfaceCards-1 downTo 1  do // I do not want the self address of 127.0.0.1
        begin
          ipAddress[reOrder] := inet_ntoa(TSockAddrIn(interfaceList[i-1].iiAddress).sin_Addr);
          reOrder := succ(reOrder);    // the cards are in the interfacelist high to low.
        end;                           // I want the order to be low to high.
      end;
      numInterfaceCards := numInterfaceCards-1;    // I do not want the self address of 127.0.0.1
    end;
  finally
    WSACleanup;
  end;
end;

function TNetCardData.GetNumOfInterfaces:integer;
var
  err: integer;
  nBytesReturned: longint;
begin
  result := -1;
  socket := WSASocket(AF_INET,SOCK_DGRAM,0,nil,0,0);
  if socket = SOCKET_ERROR then
    Exit;
  err := WSAIoctl(socket, SIO_GET_INTERFACE_LIST, nil, 0,
                  @interfaceList, sizeOf(interfaceList), @nBytesReturned, nil, nil);
  if err = 0 then
    result := nBytesReturned div sizeOf(TINTERFACE_INFO);
  closesocket(socket);
end;

end.
반응형