Bind to user-specified address (BindAddress6)
[mgsmtp.git] / DNSResolve.pas
index 6e6acff0fdf1865903370d1df911fe0461f2fb53..48ef5dd7934b0ea552492a9221dd62a7c7242521 100644 (file)
@@ -1,5 +1,5 @@
 {
-   Copyright (C) 2010 MegaBrutal
+   Copyright (C) 2010-2018 MegaBrutal
 
    This unit is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
 unit DNSResolve;
 
 interface
-uses WinSock, Sockets;
+uses WinSock, Sockets, ctypes;
 
+const
 
-   function ResolveHost(HostName: ansistring): in_addr;
-   function ResolveIP(IP: in_addr): ansistring;
+   NI_NOFQDN         =     $01;
+   NI_NUMERICHOST    =     $02;
+   NI_NAMEREQD       =     $04;
+   NI_NUMERICSERV    =     $08;
+   NI_DGRAM          =     $10;
+
+
+type
+
+   PAddrInfo = ^TAddrInfo;
+   TAddrInfo = record
+      ai_flags: cint;
+      ai_family: cint;
+      ai_socktype: cint;
+      ai_protocol: cint;
+      ai_addrlen: size_t;
+      ai_canonname: PChar;
+      ai_addr: PSockAddr;
+      ai_next: PAddrInfo;
+   end;
+
+   TGAIResult = record
+      GAIError: integer;
+      AddrInfo: PAddrInfo;
+   end;
+
+
+   function getaddrinfo(NodeName, ServiceName: PChar; Hints: PAddrInfo; var AddrInfo: PAddrInfo): cint; stdcall;
+      external 'ws2_32.dll' name 'getaddrinfo';
+
+   procedure freeaddrinfo(AddrInfo: PAddrInfo); stdcall;
+      external 'ws2_32.dll' name 'freeaddrinfo';
+
+   function getnameinfo(SockAddr: PSockAddr; SockAddrLength: cuint32; NodeBuffer: PChar; NodeBufferSize: cuint32;
+      ServiceBuffer: PChar; ServiceBufferSize: cuint32; Flags: cint): cint; stdcall;
+      external 'ws2_32.dll' name 'getnameinfo';
+
+   function ResolveHost(HostName: ansistring; Family: cint): TGAIResult;
+   procedure FreeHost(var GAIResult: TGAIResult);
+   function ResolveIP(AddrInfo: PAddrInfo; Flags: cint): ansistring; overload;
+   function ResolveIP(AddrInfo: PAddrInfo): ansistring; overload;
+   function ResolveIP(SockAddr: PSockAddr; Flags: cint): ansistring; overload;
+   function ResolveIP(SockAddr: PSockAddr): ansistring; overload;
+   function IPToStr(SockAddr: PSockAddr): ansistring;
 
 
 implementation
 
 
-function ResolveHost(HostName: ansistring): in_addr;
+function ResolveHost(HostName: ansistring; Family: cint): TGAIResult;
+var hint: TAddrInfo;
+begin
+   FillByte(hint, SizeOf(hint), 0);
+   with hint do begin
+      ai_family:= Family;
+      ai_socktype:= SOCK_STREAM;
+      ai_protocol:= IPPROTO_TCP;
+   end;
+   ResolveHost.GAIError:= getaddrinfo(PChar(HostName), nil, @hint, ResolveHost.AddrInfo);
+end;
+
+procedure FreeHost(var GAIResult: TGAIResult);
+begin
+   if GAIResult.AddrInfo <> nil then begin
+      freeaddrinfo(GAIResult.AddrInfo);
+      GAIResult.AddrInfo:= nil;
+   end;
+end;
+
+function ResolveIP(AddrInfo: PAddrInfo; Flags: cint): ansistring;
 var
-   HostEnt: PHostEnt;
+   r: integer;
+   NodeBuffer: array[0..255] of char;
 begin
-   HostEnt:= gethostbyname(PChar(HostName));
-   if HostEnt <> nil then
-      ResolveHost.s_addr:= PLongWord(HostEnt^.h_addr_list[0])^
-   else
-      ResolveHost.s_addr:= 0;
+   NodeBuffer[0]:= #0;
+   r:= getnameinfo(AddrInfo^.ai_addr, AddrInfo^.ai_addrlen, @NodeBuffer, SizeOf(NodeBuffer), nil, 0, Flags);
+   if r = 0 then ResolveIP:= PChar(@NodeBuffer)
+   else ResolveIP:= IPToStr(AddrInfo^.ai_addr);
 end;
 
-function ResolveIP(IP: in_addr): ansistring;
+function ResolveIP(AddrInfo: PAddrInfo): ansistring;
+begin
+   ResolveIP:= ResolveIP(AddrInfo, 0);
+end;
+
+function ResolveIP(SockAddr: PSockAddr; Flags: cint): ansistring;
 var
-   HostEnt: PHostEnt;
+   AddrInfo: TAddrInfo;
 begin
-   HostEnt:= gethostbyaddr(@IP, 4, AF_INET);
-   if HostEnt <> nil then
-      ResolveIP:= HostEnt^.h_name
+   AddrInfo.ai_addr:= SockAddr;
+
+   if SockAddr^.sa_family = AF_INET then
+      AddrInfo.ai_addrlen:= SizeOf(TSockAddr)
+   else if SockAddr^.sa_family = AF_INET6 then
+      AddrInfo.ai_addrlen:= SizeOf(TSockAddr6)
    else
-      ResolveIP:= NetAddrToStr(IP);
+      AddrInfo.ai_addrlen:= 0;
+
+   ResolveIP:= ResolveIP(PAddrInfo(@AddrInfo), Flags);
 end;
 
+function ResolveIP(SockAddr: PSockAddr): ansistring;
+begin
+   ResolveIP:= ResolveIP(SockAddr, 0);
+end;
+
+function IPToStr(SockAddr: PSockAddr): ansistring;
+begin
+{$IFNDEF GNI}
+   if SockAddr^.sa_family = AF_INET then
+      IPToStr:= NetAddrToStr(SockAddr^.sin_addr)
+   else if SockAddr^.sa_family = AF_INET6 then
+      IPToStr:= NetAddrToStr6(PSockAddr6(SockAddr)^.sin6_addr)
+   else
+      IPToStr:= 'unknown';
+{$ELSE}
+   IPToStr:= ResolveIP(SockAddr, NI_NUMERICHOST);
+{$ENDIF}
+end;
 
 
 end.