From f189f43099c2d791510b42da006b6599a8bb009b Mon Sep 17 00:00:00 2001 From: MegaBrutal Date: Tue, 20 Nov 2018 21:14:56 +0100 Subject: [PATCH] Bind to user-specified address (BindAddress) Bind to user-specified address for outgoing connections. modified: Common.pas modified: MgSMTP.pas modified: Network.pas modified: Relay.pas --- Common.pas | 4 +++ MgSMTP.pas | 2 +- Network.pas | 70 +++++++++++++++++++++++++++++++++++------------------ Relay.pas | 6 +++-- 4 files changed, 55 insertions(+), 27 deletions(-) diff --git a/Common.pas b/Common.pas index fadccc5..8677ead 100644 --- a/Common.pas +++ b/Common.pas @@ -74,9 +74,11 @@ type FTimeOffset: integer; FTimeOffsetStr: string; FListenAddresses: TStrings; + FBindAddress: string; public function GetVersionStr: string; property ListenAddresses: TStrings read FListenAddresses; + property BindAddress: string read FBindAddress; property Databytes: longint read FDatabytes; {property TimeCorrection: integer read FTimeCorrection;} property TimeOffset: integer read FTimeOffset; @@ -483,6 +485,8 @@ begin portlist.Free; end; + FBindAddress:= Config.ReadString('Server', 'BindAddress', '0.0.0.0'); + FDatabytes:= Config.ReadInteger('Server', 'Databytes', 1024 * 1024 * 1024); FTimeOffset:= Config.ReadInteger('Server', 'TimeOffset', Config.ReadInteger('Server', 'TimeCorrection', 0) * 100); FTimeOffsetStr:= MakeTimeOffsetStr(FTimeOffset); diff --git a/MgSMTP.pas b/MgSMTP.pas index 1627479..19dc968 100644 --- a/MgSMTP.pas +++ b/MgSMTP.pas @@ -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. } - DEVCOMMENT = 'Log actual listen address if hostname given'; + DEVCOMMENT = 'BindAddress'; var diff --git a/Network.pas b/Network.pas index cd13cb2..d19aeea 100644 --- a/Network.pas +++ b/Network.pas @@ -54,15 +54,16 @@ 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); overload; destructor Destroy; override; private FConnected: boolean; FSocket: socket; FHostIP: TIPNamePair; FSockTimeOut: DWord; - SockAddr: TSockAddr; + SrcSockAddr, DstSockAddr: TSockAddr; public + function SetBindAddress(const HostName: string): boolean; function Connect(const HostName: string; Port: word): boolean; procedure Disconnect; procedure ReverseDNSLookup; @@ -129,6 +130,8 @@ begin FConnected:= false; FSocket:= -1; FSockTimeOut:= DEF_SOCK_TIMEOUT; + FillChar(SrcSockAddr, SizeOf(SrcSockAddr), 0); + FillChar(DstSockAddr, SizeOf(DstSockAddr), 0); end; constructor TTCPConnection.Create(const HostName: string; Port: word); @@ -138,13 +141,17 @@ begin Connect(HostName, Port); end; -constructor TTCPConnection.Create(Socket: socket; const Addr: TSockAddr); +constructor TTCPConnection.Create(Socket: socket); { Use an already connected socket. } +var ssocklen, dsocklen: TSockLen; begin inherited Create; FSocket:= Socket; - SockAddr:= Addr; - FHostIP:= TIPNamePair.Create('', NetAddrToStr(Addr.sin_addr)); + ssocklen:= SizeOf(SrcSockAddr); + dsocklen:= SizeOf(DstSockAddr); + fpgetsockname(FSocket, @SrcSockAddr, @ssocklen); + fpgetpeername(FSocket, @DstSockAddr, @dsocklen); + FHostIP:= TIPNamePair.Create('', NetAddrToStr(DstSockAddr.sin_addr)); FConnected:= true; end; @@ -176,29 +183,44 @@ begin end; +function TTCPConnection.SetBindAddress(const HostName: string): boolean; +var GAIResult: TGAIResult; +begin + GAIResult:= ResolveHost(HostName); + if GAIResult.GAIError = 0 then begin + SrcSockAddr:= GAIResult.AddrInfo^.ai_addr^; + 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 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); - - 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); + if (SrcSockAddr.sin_addr.s_addr = 0) or (fpBind(FSocket, @SrcSockAddr, SizeOf(SrcSockAddr)) = 0) then begin + GAIResult:= ResolveHost(HostName); + if GAIResult.GAIError = 0 then begin + DstSockAddr:= GAIResult.AddrInfo^.ai_addr^; + DstSockAddr.sin_port:= htons(Port); + + if DstSockAddr.sin_addr.s_addr <> 0 then + { Try to initiate connection. } + FConnected:= fpConnect(FSocket, @DstSockAddr, SizeOf(DstSockAddr)) <> -1; + + if FConnected then begin + FHostIP:= TIPNamePair.Create(HostName, NetAddrToStr(DstSockAddr.sin_addr)); + SetSockTimeOut(FSockTimeOut); + end + else + CloseSocket(FSocket); - FreeHost(GAIResult); + FreeHost(GAIResult); + end; end; end; Result:= FConnected; @@ -218,7 +240,7 @@ procedure TTCPConnection.ReverseDNSLookup; var NHostIP: TIPNamePair; begin if FConnected then begin - NHostIP:= TIPNamePair.Create(ResolveIP(@SockAddr), FHostIP.IP); + NHostIP:= TIPNamePair.Create(ResolveIP(@DstSockAddr), FHostIP.IP); FHostIP.Free; FHostIP:= NHostIP; end; @@ -356,9 +378,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. } diff --git a/Relay.pas b/Relay.pas index cf38760..3df2b33 100644 --- a/Relay.pas +++ b/Relay.pas @@ -1,6 +1,6 @@ { MegaBrutal's SMTP Server (MgSMTP) - Copyright (C) 2010-2015 MegaBrutal + Copyright (C) 2010-2018 MegaBrutal This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -331,7 +331,9 @@ var MXList: TStrings; i: integer; begin MXList:= GetCorrectMXRecordList(RelayServerName); if MXList.Count >= 1 then begin - TCP:= TTCPRFCConnection.Create(MXList.Strings[0], RelayServerPort); + TCP:= TTCPRFCConnection.Create; + TCP.SetBindAddress(MainServerConfig.BindAddress); + TCP.Connect(MXList.Strings[0], RelayServerPort); TCP.SetSockTimeOut(DEF_SOCK_TIMEOUT); i:= 1; while (not TCP.Connected) and (i < MXList.Count) do begin -- 2.34.1