Use getaddrinfo & getnameinfo
authorMegaBrutal <code+git@megabrutal.com>
Fri, 26 Oct 2018 15:15:55 +0000 (17:15 +0200)
committerMegaBrutal <code+git@megabrutal.com>
Fri, 26 Oct 2018 15:15:55 +0000 (17:15 +0200)
Use getaddrinfo and getnameinfo API functions for DNS resolutions
instead of the deprecated gethostbyname and gethostbyaddr functions.

This is in preparation to IPv6 support, as getaddrinfo and getnameinfo
are agnostic to address family.

modified:   DNSResolve.pas
modified:   MgSMTP.pas
modified:   Network.pas

DNSResolve.pas
MgSMTP.pas
Network.pas

index 6e6acff0fdf1865903370d1df911fe0461f2fb53..2ca6439012e325b974d8c3df13b71bd19d6298fa 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
 
    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
 unit DNSResolve;
 
 interface
-uses WinSock, Sockets;
+uses WinSock, Sockets, ctypes;
 
 
+type
 
 
-   function ResolveHost(HostName: ansistring): in_addr;
-   function ResolveIP(IP: in_addr): ansistring;
+   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): TGAIResult;
+   procedure FreeHost(var GAIResult: TGAIResult);
+   function ResolveIP(SockAddr: PSockAddr): ansistring;
 
 
 implementation
 
 
 
 
 implementation
 
 
-function ResolveHost(HostName: ansistring): in_addr;
-var
-   HostEnt: PHostEnt;
+function ResolveHost(HostName: ansistring): TGAIResult;
+var hint: TAddrInfo;
+begin
+   FillByte(hint, SizeOf(hint), 0);
+   with hint do begin
+      ai_family:= AF_INET;
+      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
 begin
-   HostEnt:= gethostbyname(PChar(HostName));
-   if HostEnt <> nil then
-      ResolveHost.s_addr:= PLongWord(HostEnt^.h_addr_list[0])^
-   else
-      ResolveHost.s_addr:= 0;
+   if GAIResult.AddrInfo <> nil then begin
+      freeaddrinfo(GAIResult.AddrInfo);
+         GAIResult.AddrInfo:= nil;
+   end;
 end;
 
 end;
 
-function ResolveIP(IP: in_addr): ansistring;
+function ResolveIP(SockAddr: PSockAddr): ansistring;
 var
 var
-   HostEnt: PHostEnt;
+   r: integer;
+   NodeBuffer: array[0..255] of char;
 begin
 begin
-   HostEnt:= gethostbyaddr(@IP, 4, AF_INET);
-   if HostEnt <> nil then
-      ResolveIP:= HostEnt^.h_name
-   else
-      ResolveIP:= NetAddrToStr(IP);
+   NodeBuffer[0]:= #0;
+   r:= getnameinfo(SockAddr, SizeOf(TSockAddr), @NodeBuffer, SizeOf(NodeBuffer), nil, 0, 0);
+   if r = 0 then ResolveIP:= PChar(@NodeBuffer)
+   else ResolveIP:= NetAddrToStr(SockAddr^.sin_addr);
 end;
 
 
 end;
 
 
index 438f0b628423b008181a7c5785b214d8d691b5cc..a9c51e7d2e1ca64260742f5b1888f195d81b0ade 100644 (file)
@@ -49,7 +49,7 @@ const
      document what bugfix/feature are you testing with the actual build.
      This will be logged to help you differentiate outputs of subsequent
      builds in your logs. If left empty, it won't be added to the logs. }
      document what bugfix/feature are you testing with the actual build.
      This will be logged to help you differentiate outputs of subsequent
      builds in your logs. If left empty, it won't be added to the logs. }
-   DEVCOMMENT  =  'Wine 1.6 AddStdLine fix';
+   DEVCOMMENT  =  'Use getaddrinfo & getnameinfo';
 
 var
 
 
 var
 
index 10a95f991d3898060489ecfdc31d252c242b81d7..d5b458da2d5919570e2805ae5416b63eac408752 100644 (file)
@@ -61,7 +61,7 @@ type
       FSocket: socket;
       FHostIP: TIPNamePair;
       FSockTimeOut: DWord;
       FSocket: socket;
       FHostIP: TIPNamePair;
       FSockTimeOut: DWord;
-      sAddr: TSockAddr;
+      SockAddr: TSockAddr;
    public
       function Connect(const HostName: string; Port: word): boolean;
       procedure Disconnect;
    public
       function Connect(const HostName: string; Port: word): boolean;
       procedure Disconnect;
@@ -106,7 +106,7 @@ type
       FListenAddress: string;
       FListenPort: word;
       FListenSocket: socket;
       FListenAddress: string;
       FListenPort: word;
       FListenSocket: socket;
-      sAddr: TSockAddr;
+      SockAddr: TSockAddr;
    protected
       procedure HandleClient(Connection: TTCPConnection); virtual; abstract;
       procedure Execute; override;
    protected
       procedure HandleClient(Connection: TTCPConnection); virtual; abstract;
       procedure Execute; override;
@@ -133,7 +133,7 @@ end;
 constructor TTCPConnection.Create(const HostName: string; Port: word);
 { Connect to the given port on the given hostname. }
 begin
 constructor TTCPConnection.Create(const HostName: string; Port: word);
 { Connect to the given port on the given hostname. }
 begin
-   inherited Create;
+   Create;
    Connect(HostName, Port);
 end;
 
    Connect(HostName, Port);
 end;
 
@@ -142,7 +142,7 @@ constructor TTCPConnection.Create(Socket: socket; const Addr: TSockAddr);
 begin
    inherited Create;
    FSocket:= Socket;
 begin
    inherited Create;
    FSocket:= Socket;
-   sAddr:= Addr;
+   SockAddr:= Addr;
    FHostIP:= TIPNamePair.Create('', NetAddrToStr(Addr.sin_addr));
    FConnected:= true;
 end;
    FHostIP:= TIPNamePair.Create('', NetAddrToStr(Addr.sin_addr));
    FConnected:= true;
 end;
@@ -170,32 +170,35 @@ begin
    FListenPort:= Port;
    FFeatureRequest:= FeatureRequest;
    FreeOnTerminate:= false;
    FListenPort:= Port;
    FFeatureRequest:= FeatureRequest;
    FreeOnTerminate:= false;
+   FillChar(SockAddr, SizeOf(SockAddr), 0);
    inherited Create(true);
 end;
 
 
 function TTCPConnection.Connect(const HostName: string; Port: word): boolean;
 { Resolves the given hostname, and tries to connect it on the given port. }
    inherited Create(true);
 end;
 
 
 function TTCPConnection.Connect(const HostName: string; Port: word): boolean;
 { Resolves the given hostname, and tries to connect it on the given port. }
+var GAIResult: TGAIResult;
 begin
    FSocket:= fpSocket(af_inet, sock_stream, 0);
    if (FSocket <> -1) then begin
 begin
    FSocket:= fpSocket(af_inet, sock_stream, 0);
    if (FSocket <> -1) then begin
-      with sAddr do begin
-         sin_family:= af_inet;
-         sin_port:= htons(Port);
-         { Resolve hostname to IP address. }
-         sin_addr:= ResolveHost(HostName);
+      GAIResult:= ResolveHost(HostName);
+         if GAIResult.GAIError = 0 then begin
+            SockAddr:= GAIResult.AddrInfo^.ai_addr^;
+                SockAddr.sin_port:= htons(Port);
+
+                if SockAddr.sin_addr.s_addr <> 0 then
+                   { Try to initiate connection. }
+                   FConnected:= fpConnect(FSocket, @SockAddr, SizeOf(SockAddr)) <> -1;
+
+                if FConnected then begin
+                   FHostIP:= TIPNamePair.Create(HostName, NetAddrToStr(SockAddr.sin_addr));
+                   SetSockTimeOut(FSockTimeOut);
+                end
+                else
+                   CloseSocket(FSocket);
+
+         FreeHost(GAIResult);
       end;
       end;
-
-      if sAddr.sin_addr.s_addr <> 0 then
-         { Try to initiate connection. }
-         FConnected:= fpConnect(FSocket, @sAddr, SizeOf(sAddr)) <> -1;
-
-      if FConnected then begin
-         FHostIP:= TIPNamePair.Create(HostName, NetAddrToStr(sAddr.sin_addr));
-         SetSockTimeOut(FSockTimeOut);
-      end
-      else
-         CloseSocket(FSocket);
    end;
    Result:= FConnected;
 end;
    end;
    Result:= FConnected;
 end;
@@ -214,15 +217,25 @@ procedure TTCPConnection.ReverseDNSLookup;
 var NHostIP: TIPNamePair;
 begin
    if FConnected then begin
 var NHostIP: TIPNamePair;
 begin
    if FConnected then begin
-      NHostIP:= TIPNamePair.Create(ResolveIP(sAddr.sin_addr), FHostIP.IP);
+      NHostIP:= TIPNamePair.Create(ResolveIP(@SockAddr), FHostIP.IP);
       FHostIP.Free;
       FHostIP:= NHostIP;
    end;
 end;
 
 function TTCPConnection.VerifyFCrDNS: boolean;
       FHostIP.Free;
       FHostIP:= NHostIP;
    end;
 end;
 
 function TTCPConnection.VerifyFCrDNS: boolean;
+var GAIResult: TGAIResult; ai: PAddrInfo;
 begin
 begin
-   Result:= NetAddrToStr(ResolveHost(HostIP.Name)) = HostIP.IP;
+   Result:= false;
+   GAIResult:= ResolveHost(HostIP.Name);
+   if GAIResult.GAIError = 0 then begin
+      ai:= GAIResult.AddrInfo;
+         { One of the addresses must match. }
+         while (ai <> nil) and not Result do begin
+            Result:= NetAddrToStr(ai^.ai_addr^.sin_addr) = HostIP.IP;
+                ai:= ai^.ai_next;
+      end;
+   end;
 end;
 
 procedure TTCPConnection.SetSockTimeOut(TimeOut: DWord);
 end;
 
 procedure TTCPConnection.SetSockTimeOut(TimeOut: DWord);
@@ -288,24 +301,29 @@ end;
 
 
 function TTCPListener.StartListen: boolean;
 
 
 function TTCPListener.StartListen: boolean;
+var GAIResult: TGAIResult;
 begin
    FListenSocket:= fpSocket(af_inet, sock_stream, 0);
    if FListenSocket <> -1 then begin
 begin
    FListenSocket:= fpSocket(af_inet, sock_stream, 0);
    if FListenSocket <> -1 then begin
-      with sAddr do begin
-         sin_family:= af_inet;
-         sin_port:= htons(FListenPort);
-         sin_addr:= ResolveHost(FListenAddress);
-      end;
-      if fpBind(FListenSocket, @sAddr, sizeof(sAddr)) <> -1 then begin
-         { It seems the maximum connection value isn't enforced by the
-           Free Pascal library, so this 512 is a constant, dummy value. }
-         if fpListen(FListenSocket, 512) <> -1 then begin
-            Result:= true;
-            Start;
+      GAIResult:= ResolveHost(FListenAddress);
+         if GAIResult.GAIError = 0 then begin
+            SockAddr:= GAIResult.AddrInfo^.ai_addr^;
+                SockAddr.sin_port:= htons(FListenPort);
+
+         if fpBind(FListenSocket, @SockAddr, SizeOf(SockAddr)) <> -1 then begin
+            { It seems the maximum connection value isn't enforced by the
+              Free Pascal library, so this 512 is a constant, dummy value. }
+            if fpListen(FListenSocket, 512) <> -1 then begin
+               Result:= true;
+               Start;
+            end
+            else Result:= false;
          end
          else Result:= false;
          end
          else Result:= false;
+
+         FreeHost(GAIResult);
       end
       end
-      else Result:= false;
+         else Result:= false;
    end
    else Result:= false;
 end;
    end
    else Result:= false;
 end;
@@ -323,8 +341,8 @@ begin
    { Now, accept connections. }
    AcceptFailCount:= 0;
    while not Terminated do begin
    { Now, accept connections. }
    AcceptFailCount:= 0;
    while not Terminated do begin
-      Len:= SizeOf(sAddr);
-      ClientSocket:= fpAccept(FListenSocket, @sAddr, @Len);
+      Len:= SizeOf(SockAddr);
+      ClientSocket:= fpAccept(FListenSocket, @SockAddr, @Len);
       if ClientSocket <> -1 then begin
          AcceptFailCount:= 0;
 
       if ClientSocket <> -1 then begin
          AcceptFailCount:= 0;
 
@@ -332,9 +350,9 @@ begin
            connection. }
          case FFeatureRequest of
          NET_TCP_BASIC:
            connection. }
          case FFeatureRequest of
          NET_TCP_BASIC:
-            TCPConnection:= TTCPConnection.Create(ClientSocket, sAddr);
+            TCPConnection:= TTCPConnection.Create(ClientSocket, SockAddr);
          NET_TCP_RFCSUPPORT:
          NET_TCP_RFCSUPPORT:
-            TCPConnection:= TTCPRFCConnection.Create(ClientSocket, sAddr);
+            TCPConnection:= TTCPRFCConnection.Create(ClientSocket, SockAddr);
          end;
 
          { Then start a new thread with the connection handler. }
          end;
 
          { Then start a new thread with the connection handler. }