Bind to user-specified address (BindAddress)
authorMegaBrutal <code+git@megabrutal.com>
Tue, 20 Nov 2018 20:14:56 +0000 (21:14 +0100)
committerMegaBrutal <code+git@megabrutal.com>
Wed, 21 Nov 2018 15:05:21 +0000 (16:05 +0100)
Bind to user-specified address for outgoing connections.

modified:   Common.pas
modified:   MgSMTP.pas
modified:   Network.pas
modified:   Relay.pas

Common.pas
MgSMTP.pas
Network.pas
Relay.pas

index fadccc59f8b17f0ca294d84740c7af03e946d546..8677ead2930bae7372d9145358cc90233f6cc6d0 100644 (file)
@@ -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);
index 1627479c1b590e297992f1b9cc437d57652db626..19dc9685e13a0960decb1bff1401374d051f8885 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. }
-   DEVCOMMENT  =  'Log actual listen address if hostname given';
+   DEVCOMMENT  =  'BindAddress';
 
 var
 
index cd13cb2ae4740ec5368c70686d381395fbd14660..d19aeeacbda844998fea48c0701f40c7cf56afeb 100644 (file)
@@ -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. }
index cf3876027bef390a883e18f7771258ceced65416..3df2b330ca14ec3d79d61d5200980f7f74597ded 100644 (file)
--- 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