From: MegaBrutal Date: Tue, 30 Oct 2018 00:55:55 +0000 (+0100) Subject: Add IPv6 support to Network unit X-Git-Url: http://git.megabrutal.com/?p=mgsmtp.git;a=commitdiff_plain;h=461ab8aed63976eed05ba159c4dbfa4baa06d33b Add IPv6 support to Network unit Made the DNSResolve and Network units IP version agnostic. modified: DNSResolve.pas modified: Network.pas --- diff --git a/DNSResolve.pas b/DNSResolve.pas index 2ca6439..fb4b467 100644 --- a/DNSResolve.pas +++ b/DNSResolve.pas @@ -53,20 +53,21 @@ type ServiceBuffer: PChar; ServiceBufferSize: cuint32; Flags: cint): cint; stdcall; external 'ws2_32.dll' name 'getnameinfo'; - function ResolveHost(HostName: ansistring): TGAIResult; + function ResolveHost(HostName: ansistring; Family: cint): TGAIResult; procedure FreeHost(var GAIResult: TGAIResult); - function ResolveIP(SockAddr: PSockAddr): ansistring; + function ResolveIP(AddrInfo: PAddrInfo): ansistring; + function IPToStr(SockAddr: PSockAddr): ansistring; implementation -function ResolveHost(HostName: ansistring): TGAIResult; +function ResolveHost(HostName: ansistring; Family: cint): TGAIResult; var hint: TAddrInfo; begin FillByte(hint, SizeOf(hint), 0); with hint do begin - ai_family:= AF_INET; + ai_family:= Family; ai_socktype:= SOCK_STREAM; ai_protocol:= IPPROTO_TCP; end; @@ -77,21 +78,30 @@ procedure FreeHost(var GAIResult: TGAIResult); begin if GAIResult.AddrInfo <> nil then begin freeaddrinfo(GAIResult.AddrInfo); - GAIResult.AddrInfo:= nil; + GAIResult.AddrInfo:= nil; end; end; -function ResolveIP(SockAddr: PSockAddr): ansistring; +function ResolveIP(AddrInfo: PAddrInfo): ansistring; var r: integer; NodeBuffer: array[0..255] of char; begin NodeBuffer[0]:= #0; - r:= getnameinfo(SockAddr, SizeOf(TSockAddr), @NodeBuffer, SizeOf(NodeBuffer), nil, 0, 0); + r:= getnameinfo(AddrInfo^.ai_addr, AddrInfo^.ai_addrlen, @NodeBuffer, SizeOf(NodeBuffer), nil, 0, 0); if r = 0 then ResolveIP:= PChar(@NodeBuffer) - else ResolveIP:= NetAddrToStr(SockAddr^.sin_addr); + else ResolveIP:= IPToStr(AddrInfo^.ai_addr); end; +function IPToStr(SockAddr: PSockAddr): ansistring; +begin + 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'; +end; end. diff --git a/Network.pas b/Network.pas index d5b458d..b19dd7d 100644 --- a/Network.pas +++ b/Network.pas @@ -54,14 +54,14 @@ type TTCPConnection = class constructor Create; overload; constructor Create(const HostName: string; Port: word); overload; - constructor Create(Socket: socket; const Addr: TSockAddr); overload; + constructor Create(Socket: socket; const Addr: TSockAddr6); overload; destructor Destroy; override; private FConnected: boolean; FSocket: socket; FHostIP: TIPNamePair; FSockTimeOut: DWord; - SockAddr: TSockAddr; + SockAddr: TSockAddr6; public function Connect(const HostName: string; Port: word): boolean; procedure Disconnect; @@ -99,14 +99,15 @@ type end; TTCPListener = class(TThread) - constructor Create(const Address: string; Port: word; FeatureRequest: word); + constructor Create(const Address: string; Port: word; Family: word; FeatureRequest: word); {destructor Destroy; override;} private FFeatureRequest: word; + FFamily: word; FListenAddress: string; FListenPort: word; FListenSocket: socket; - SockAddr: TSockAddr; + SockAddr: TSockAddr6; protected procedure HandleClient(Connection: TTCPConnection); virtual; abstract; procedure Execute; override; @@ -137,13 +138,13 @@ begin Connect(HostName, Port); end; -constructor TTCPConnection.Create(Socket: socket; const Addr: TSockAddr); +constructor TTCPConnection.Create(Socket: socket; const Addr: TSockAddr6); { Use an already connected socket. } begin inherited Create; FSocket:= Socket; SockAddr:= Addr; - FHostIP:= TIPNamePair.Create('', NetAddrToStr(Addr.sin_addr)); + FHostIP:= TIPNamePair.Create('', IPToStr(@Addr)); FConnected:= true; end; @@ -164,8 +165,9 @@ begin end; -constructor TTCPListener.Create(const Address: string; Port: word; FeatureRequest: word); +constructor TTCPListener.Create(const Address: string; Port: word; Family: word; FeatureRequest: word); begin + FFamily:= Family; FListenAddress:= Address; FListenPort:= Port; FFeatureRequest:= FeatureRequest; @@ -181,17 +183,16 @@ var GAIResult: TGAIResult; begin FSocket:= fpSocket(af_inet, sock_stream, 0); if (FSocket <> -1) then begin - GAIResult:= ResolveHost(HostName); - if GAIResult.GAIError = 0 then begin - SockAddr:= GAIResult.AddrInfo^.ai_addr^; - SockAddr.sin_port:= htons(Port); + GAIResult:= ResolveHost(HostName, AF_UNSPEC); + if GAIResult.GAIError = 0 then begin + Move(GAIResult.AddrInfo^.ai_addr^, SockAddr, GAIResult.AddrInfo^.ai_addrlen); + SockAddr.sin6_port:= htons(Port); - if SockAddr.sin_addr.s_addr <> 0 then - { Try to initiate connection. } - FConnected:= fpConnect(FSocket, @SockAddr, SizeOf(SockAddr)) <> -1; + { Try to initiate connection. } + FConnected:= fpConnect(FSocket, @SockAddr, GAIResult.AddrInfo^.ai_addrlen) <> -1; if FConnected then begin - FHostIP:= TIPNamePair.Create(HostName, NetAddrToStr(SockAddr.sin_addr)); + FHostIP:= TIPNamePair.Create(HostName, IPToStr(@SockAddr)); SetSockTimeOut(FSockTimeOut); end else @@ -227,13 +228,13 @@ function TTCPConnection.VerifyFCrDNS: boolean; var GAIResult: TGAIResult; ai: PAddrInfo; begin Result:= false; - GAIResult:= ResolveHost(HostIP.Name); + GAIResult:= ResolveHost(HostIP.Name, AF_UNSPEC); 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; + { One of the addresses must match. } + while (ai <> nil) and not Result do begin + Result:= IPToStr(ai^.ai_addr) = HostIP.IP; + ai:= ai^.ai_next; end; end; end; @@ -303,14 +304,14 @@ end; function TTCPListener.StartListen: boolean; var GAIResult: TGAIResult; begin - FListenSocket:= fpSocket(af_inet, sock_stream, 0); + FListenSocket:= fpSocket(FFamily, SOCK_STREAM, 0); if FListenSocket <> -1 then begin - GAIResult:= ResolveHost(FListenAddress); - if GAIResult.GAIError = 0 then begin - SockAddr:= GAIResult.AddrInfo^.ai_addr^; - SockAddr.sin_port:= htons(FListenPort); + GAIResult:= ResolveHost(FListenAddress, FFamily); + if GAIResult.GAIError = 0 then begin + Move(GAIResult.AddrInfo^.ai_addr^, SockAddr, GAIResult.AddrInfo^.ai_addrlen); + SockAddr.sin6_port:= htons(FListenPort); - if fpBind(FListenSocket, @SockAddr, SizeOf(SockAddr)) <> -1 then begin + if fpBind(FListenSocket, @SockAddr, GAIResult.AddrInfo^.ai_addrlen) <> -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