X-Git-Url: http://git.megabrutal.com/?p=mgsmtp.git;a=blobdiff_plain;f=Network.pas;h=a28ff634077b64e0a77e8c36be148ead9d515017;hp=ec602d1a8995022c6c12ec3a21766d988d49f037;hb=7c2747623547f74cab3bdb565b24edbd81fef086;hpb=54baea76c00e60c3e49bc3a3fa4292cf637dfbf9 diff --git a/Network.pas b/Network.pas index ec602d1..a28ff63 100644 --- a/Network.pas +++ b/Network.pas @@ -37,7 +37,7 @@ unit Network; interface -uses Classes, Sockets, SocketUtils, DNSResolve, NetRFC, Common; +uses Classes, Sockets, SocketUtils, ctypes, DNSResolve, NetRFC, Common; const @@ -61,15 +61,21 @@ type TTCPConnection = class constructor Create; overload; constructor Create(const HostName: string; Port: word); overload; - constructor Create(Socket: socket; const Addr: TSockAddr6); overload; + constructor Create(Socket: socket); overload; destructor Destroy; override; private FConnected: boolean; FSocket: socket; FHostIP: TIPNamePair; FSockTimeOut: DWord; - SockAddr: TSockAddr6; + SrcSockAddr: TSockAddr; + SrcSockAddr6: TSockAddr6; + DstSockAddr: TSockAddr6; + protected + function IsNullAddress(SockAddr: PSockAddr): boolean; + function BindSrcAddr(Socket: socket; Family: word): cint; public + function SetBindAddress(Family: word; const HostName: string): boolean; function Connect(const HostName: string; Port: word): boolean; procedure Disconnect; procedure ReverseDNSLookup; @@ -136,6 +142,11 @@ begin FConnected:= false; FSocket:= -1; FSockTimeOut:= DEF_SOCK_TIMEOUT; + FillChar(SrcSockAddr, SizeOf(SrcSockAddr), 0); + FillChar(SrcSockAddr6, SizeOf(SrcSockAddr6), 0); + FillChar(DstSockAddr, SizeOf(DstSockAddr), 0); + SrcSockAddr.sin_family:= AF_INET; + SrcSockAddr6.sin6_family:= AF_INET6; end; constructor TTCPConnection.Create(const HostName: string; Port: word); @@ -145,13 +156,17 @@ begin Connect(HostName, Port); end; -constructor TTCPConnection.Create(Socket: socket; const Addr: TSockAddr6); +constructor TTCPConnection.Create(Socket: socket); { Use an already connected socket. } +var ssocklen, dsocklen: TSockLen; begin inherited Create; FSocket:= Socket; - SockAddr:= Addr; - FHostIP:= TIPNamePair.Create('', IPToStr(@Addr)); + ssocklen:= SizeOf(SrcSockAddr); + dsocklen:= SizeOf(DstSockAddr); + fpgetsockname(FSocket, @SrcSockAddr, @ssocklen); + fpgetpeername(FSocket, @DstSockAddr, @dsocklen); + FHostIP:= TIPNamePair.Create('', IPToStr(@DstSockAddr)); FConnected:= true; end; @@ -184,26 +199,84 @@ begin end; +function TTCPConnection.IsNullAddress(SockAddr: PSockAddr): boolean; +begin + if SockAddr^.sin_family = AF_INET then + Result:= SockAddr^.sin_addr.s_addr = 0 + else if SockAddr^.sin_family = AF_INET6 then + Result:= (PSockAddr6(SockAddr)^.sin6_addr.u6_addr32[0] = 0) + and (PSockAddr6(SockAddr)^.sin6_addr.u6_addr32[1] = 0) + and (PSockAddr6(SockAddr)^.sin6_addr.u6_addr32[2] = 0) + and (PSockAddr6(SockAddr)^.sin6_addr.u6_addr32[3] = 0) + else + Result:= true; +end; + +function TTCPConnection.BindSrcAddr(Socket: socket; Family: word): cint; +var SockAddr: PSockAddr; addrlen: size_t; +begin + case Family of + AF_INET: + begin + SockAddr:= @SrcSockAddr; + addrlen:= SizeOf(SrcSockAddr); + end; + AF_INET6: + begin + SockAddr:= @SrcSockAddr6; + addrlen:= SizeOf(SrcSockAddr6); + end; + end; + + if not IsNullAddress(SockAddr) then + Result:= fpBind(Socket, SockAddr, addrlen) + else + Result:= 0; +end; + +function TTCPConnection.SetBindAddress(Family: word; const HostName: string): boolean; +var GAIResult: TGAIResult; SockAddr: PSockAddr; +begin + GAIResult:= ResolveHost(HostName, Family); + if GAIResult.GAIError = 0 then begin + case GAIResult.AddrInfo^.ai_family of + AF_INET: SockAddr:= @SrcSockAddr; + AF_INET6: SockAddr:= @SrcSockAddr6; + end; + Move(GAIResult.AddrInfo^.ai_addr^, SockAddr^, GAIResult.AddrInfo^.ai_addrlen); + FreeHost(GAIResult); + Result:= true; + end + else + Result:= false; +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 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); + Move(GAIResult.AddrInfo^.ai_addr^, DstSockAddr, GAIResult.AddrInfo^.ai_addrlen); + DstSockAddr.sin6_port:= htons(Port); { Create socket. } FSocket:= fpSocket(GAIResult.AddrInfo^.ai_family, SOCK_STREAM, 0); if (FSocket <> -1) then begin - { Try to initiate connection. } - FConnected:= fpConnect(FSocket, @SockAddr, GAIResult.AddrInfo^.ai_addrlen) <> -1; + if BindSrcAddr(FSocket, GAIResult.AddrInfo^.ai_family) = 0 then begin + + { Try to initiate connection. } + FConnected:= fpConnect(FSocket, @DstSockAddr, GAIResult.AddrInfo^.ai_addrlen) <> -1; + + if FConnected then begin + FHostIP:= TIPNamePair.Create(HostName, IPToStr(@DstSockAddr)); + SetSockTimeOut(FSockTimeOut); + end + else + CloseSocket(FSocket); - if FConnected then begin - FHostIP:= TIPNamePair.Create(HostName, IPToStr(@SockAddr)); - SetSockTimeOut(FSockTimeOut); end else CloseSocket(FSocket); @@ -229,7 +302,7 @@ procedure TTCPConnection.ReverseDNSLookup; var NHostIP: TIPNamePair; begin if FConnected then begin - NHostIP:= TIPNamePair.Create(ResolveIP(PSockAddr(@SockAddr)), FHostIP.IP); + NHostIP:= TIPNamePair.Create(ResolveIP(PSockAddr(@DstSockAddr)), FHostIP.IP); FHostIP.Free; FHostIP:= NHostIP; end; @@ -362,9 +435,9 @@ begin connection. } case FFeatureRequest of NET_TCP_BASIC: - TCPConnection:= TTCPConnection.Create(ClientSocket, SockAddr); + TCPConnection:= TTCPConnection.Create(ClientSocket); NET_TCP_RFCSUPPORT: - TCPConnection:= TTCPRFCConnection.Create(ClientSocket, SockAddr); + TCPConnection:= TTCPRFCConnection.Create(ClientSocket); end; { Then start a new thread with the connection handler. }