/* This little program demonstrates the parsing of IPAddress strings */
int main(int argc, char ** argv)
{
   CompleteSetupSystem css;

   PrintExampleDescription();

   while(1)
   {
      printf("Please enter a string representing an IPv4 or IPv6 numeric host-address: ");
      fflush(stdout);

      char buf[1024];
      (void) fgets(buf, sizeof(buf), stdin);

      String s = buf;
      s = s.Trim();  // get rid of newline ugliness

      IPAddress ip;
      if (ip.SetFromString(s) == B_NO_ERROR)
      {
         printf("I parsed the string [%s] as IPAddress %s\n", s(), ip.ToString()());
         printf("    ip.IsValid() returned %i\n", ip.IsValid());
         printf("    ip.IsIPv4() returned %i\n", ip.IsIPv4());
         printf("    ip.IsMulticast() returned %i\n", ip.IsMulticast());
         printf("    ip.IsStandardLoopbackAddress() returned %i\n", ip.IsStandardLoopbackDeviceAddress());
         printf("\n");
      }
      else printf("Error, couldn't parse [%s] as an IPAddress!\n", s());
   }
   return 0;
}
Example #2
0
   bool
   BLCheck::ClientExistsInDNSBL(const IPAddress &sClientIP, const String &sDNSBLHost, const String &sExpectedResult)
   {
      String sReverted = GetRevertedIP(sClientIP.ToString());
      if (sReverted.GetLength() == 0)
         return false;

      String sCheckHost = sReverted + "." + sDNSBLHost;

      std::vector<String> foundAddresses;
      DNSResolver resolver;
      resolver.GetARecords(sCheckHost, foundAddresses);

      bool isBlocked = false;

      // It's possible to specify that one or many intervals are blocked,
      // using syntax such as 127.0.0.1-5|127.0.0.10-3
      const std::set<String> blockedAddresses = ExpandAddresses(sExpectedResult);

      //
      // The server may return a list of addresses.
      //
      for(const String foundAddress : foundAddresses)
      {
         // Go through all list of blocked addresses and see if host is in it.
         for(const String &blockedAddress : blockedAddresses)
         {
            // We not only support ranges, we support wildcards as well.
            isBlocked = StringParser::WildcardMatch(blockedAddress, foundAddress);

            if (isBlocked)
            {
               // We have a match. No need to continue now.
               break;
            }
         }
         
		 if (isBlocked)
         {
            // We have a match. No need to continue.
            break;
         }
      }

      // If a message is rejected, it's good to mention in the log which DNSBL
      // caused the rejection...
      // http://www.hmailserver.com/forum/viewtopic.php?f=10&t=16221
      //
      String foundAddressesJoined = StringParser::JoinVector(foundAddresses, ", ");
      if (foundAddressesJoined.IsEmpty())
         foundAddressesJoined = "(none)";

      String logMessage = Formatter::Format("DNS lookup: {0}, {1} addresses found: {2}, Match: {3}", sCheckHost, foundAddresses.size(), foundAddressesJoined, isBlocked);
      LOG_SMTP(0,"TCP",logMessage);

      return isBlocked;
   }
Example #3
0
bool
IPAddress::WithinRange(const IPAddress &lower, const IPAddress &upper) const
{
#ifdef _DEBUG
    String lower1 = lower.ToString();
    String lower2 = upper.ToString();
    String thisIP = ToString();
#endif

    if (GetAddress1() < lower.GetAddress1() || GetAddress1() > upper.GetAddress1())
        return false;

    // If it's an IPv4 address, we don't need to compare the second part.
    if (_address.is_v4())
        return true;

    if (GetAddress2() < lower.GetAddress2() || GetAddress2() > upper.GetAddress2())
        return false;

    return true;
}
Example #4
0
   String 
   TCPConnection::SafeGetIPAddress()
   {
      try
      {
         IPAddress address = socket_.remote_endpoint().address();

         return address.ToString();
      }
      catch (...)
      {
         return "";
      }
   }
Example #5
0
   bool
   TCPServer::FireOnAcceptEvent(const IPAddress &remoteAddress, int port)
   {
      // Fire an event...
      if (!Configuration::Instance()->GetUseScriptServer())
         return true;

      shared_ptr<ClientInfo> pCliInfo = shared_ptr<ClientInfo>(new ClientInfo);
      pCliInfo->SetIPAddress(remoteAddress.ToString());
      pCliInfo->SetPort(port);

      shared_ptr<ScriptObjectContainer> pContainer = shared_ptr<ScriptObjectContainer>(new ScriptObjectContainer);
      shared_ptr<Result> pResult = shared_ptr<Result>(new Result);

      pContainer->AddObject("Result", pResult, ScriptObject::OTResult);
      pContainer->AddObject("HMAILSERVER_CLIENT", pCliInfo, ScriptObject::OTClient);

      String sEventCaller;

      String sScriptLanguage = Configuration::Instance()->GetScriptLanguage();

      if (sScriptLanguage == _T("VBScript"))
         sEventCaller.Format(_T("OnClientConnect(HMAILSERVER_CLIENT)"));
      else if (sScriptLanguage == _T("JScript"))
         sEventCaller.Format(_T("OnClientConnect(HMAILSERVER_CLIENT);"));

      ScriptServer::Instance()->FireEvent(ScriptServer::EventOnClientConnect, sEventCaller, pContainer);

      switch (pResult->GetValue())
      {
      case 1:
         {
            // Disconnect the socket immediately.
            return false;
         }
      }

      return true;
   }
Example #6
0
////////////////////////////////////////////////////////////
/// Send an array of bytes
////////////////////////////////////////////////////////////
Socket::Status SocketUDP::Send(const char* Data, std::size_t Size, const IPAddress& Address, unsigned short Port)
{
    // Make sure the socket is valid
    if (!IsValid())
        Create();

    // Check parameters
    if (Data && Size)
    {
        // Build the target address
        sockaddr_in Target;
        Target.sin_family      = AF_INET;
        Target.sin_port        = htons(Port);
        Target.sin_addr.s_addr = inet_addr(Address.ToString().c_str());
        memset(Target.sin_zero, 0, sizeof(Target.sin_zero));

        // Loop until every byte has been sent
        int Sent = 0;
        int SizeToSend = static_cast<int>(Size);
        for (int Length = 0; Length < SizeToSend; Length += Sent)
        {
            // Send a chunk of data
            Sent = (int)sendto(mySocket, Data + Length, SizeToSend - Length, 0, reinterpret_cast<sockaddr*>(&Target), sizeof(Target));

            // Check errors
            if (Sent <= 0)
                return SocketHelper::GetErrorStatus();
        }

        return Socket::Done;
    }
    else
    {
        // Error...
        std::cerr << "Cannot send data over the network (invalid parameters)" << std::endl;
        return Socket::Error;
    }
}
Example #7
0
////////////////////////////////////////////////////////////
/// Connect to another computer on a specified port
////////////////////////////////////////////////////////////
bool SocketTCP::Connect(unsigned short Port, const IPAddress& HostAddress)
{
    // Make sure our socket is valid
    if (!IsValid())
        Create();

    // Build the host address
    sockaddr_in SockAddr;
    memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero));
    SockAddr.sin_addr.s_addr = inet_addr(HostAddress.ToString().c_str());
    SockAddr.sin_family      = AF_INET;
    SockAddr.sin_port        = htons(Port);

    // Connect
    if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
    {
        // Error...
        std::cerr << "Failed to connect socket to host " << HostAddress << std::endl;
        return false;
    }

    return true;
}
////////////////////////////////////////////////////////////
/// Connect to another computer on a specified port
////////////////////////////////////////////////////////////
Socket::Status SocketTCP::Connect(unsigned short Port, const IPAddress& HostAddress, float Timeout)
{
    // Make sure our socket is valid
    if (!IsValid())
        Create();

    // Build the host address
    sockaddr_in SockAddr;
    memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero));
    SockAddr.sin_addr.s_addr = inet_addr(HostAddress.ToString().c_str());
    SockAddr.sin_family      = AF_INET;
    SockAddr.sin_port        = htons(Port);

    if (Timeout <= 0)
    {
        // ----- We're not using a timeout : just try to connect -----

        if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
        {
            // Failed to connect
            return SocketHelper::GetErrorStatus();
        }

        // Connection succeeded
        return Socket::Done;
    }
    else
    {
        // ----- We're using a timeout : we'll need a few tricks to make it work -----

        // Save the previous blocking state
        bool IsBlocking = myIsBlocking;

        // Switch to non-blocking to enable our connection timeout
        if (IsBlocking)
            SetBlocking(false);

        // Try to connect to host
        if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) >= 0)
        {
            // We got instantly connected! (it may no happen a lot...)
            return Socket::Done;
        }

        // Get the error status
        Socket::Status Status = SocketHelper::GetErrorStatus();

        // If we were in non-blocking mode, return immediatly
        if (!IsBlocking)
            return Status;

        // Otherwise, wait until something happens to our socket (success, timeout or error)
        if (Status == Socket::NotReady)
        {
            // Setup the selector
            fd_set Selector;
            FD_ZERO(&Selector);
            FD_SET(mySocket, &Selector);

            // Setup the timeout
            timeval Time;
            Time.tv_sec  = static_cast<long>(Timeout);
            Time.tv_usec = (static_cast<long>(Timeout * 1000) % 1000) * 1000;

            // Wait for something to write on our socket (would mean the connection has been accepted)
            if (select(static_cast<int>(mySocket + 1), NULL, &Selector, NULL, &Time) > 0)
            {
                // Connection succeeded
                Status = Socket::Done;
            }
            else
            {
                // Failed to connect before timeout is over
                Status = SocketHelper::GetErrorStatus();
            }
        }

        // Switch back to blocking mode
        SetBlocking(true);

        return Status;
    }
}
Example #9
0
   bool
   TCPConnection::Connect(const AnsiString &remote_ip_address, long remotePort, const IPAddress &localAddress)
   {
#if _DEBUG
      if (!StringParser::IsValidIPAddress(remote_ip_address))
      {
         ErrorManager::Instance()->ReportError(ErrorManager::High, 5506, "TCPConnection::Connect", 
            Formatter::Format("Attempting to connect to {0} - Not a valid IP address.", remote_ip_address));
      }
#endif

      remote_port_ = remotePort;
      remote_ip_address_ = remote_ip_address;
      is_client_ = true;

      LOG_TCPIP(Formatter::Format("Connecting to {0}:{1}...", remote_ip_address_, remotePort));

      if (!localAddress.IsAny())
      {
         boost::system::error_code error_code;

         if (localAddress.GetType() == IPAddress::IPV4)
            socket_.open(boost::asio::ip::tcp::v4(), error_code);
         else if (localAddress.GetType() == IPAddress::IPV6)
            socket_.open(boost::asio::ip::tcp::v6(), error_code);

         if (error_code)
         {
            String errorMessage = Formatter::Format("Failed to open local socket on IP address {0}", localAddress.ToString());
            OnCouldNotConnect(errorMessage);
            ReportError(ErrorManager::Medium, 5520, "TCPConnection::Connect", errorMessage, error_code);
            return false;
         }

         socket_.bind(boost::asio::ip::tcp::endpoint(localAddress.GetAddress(), 0), error_code);


         if (error_code)
         {
            String errorMessage = Formatter::Format("Failed to bind to IP address {0}.", localAddress.ToString());
            ReportError(ErrorManager::Medium, 4330, "TCPConnection::Connect", errorMessage, error_code);
            OnCouldNotConnect(errorMessage);

            boost::system::error_code ignored_error_code;
            socket_.close(ignored_error_code);
            return false;
         }
      }

      // Start an asynchronous resolve to translate the server and service names
      // into a list of endpoints.
      StartAsyncConnect_(remote_ip_address, remotePort);
      return true;
   }
Example #10
0
   bool
   TestConnect::PerformTest(const String  &localAddressStr, const String &server, int port, String &result)
   {
      boost::asio::io_service io_service;

      IPAddress localAddress;
      if (!localAddressStr.IsEmpty())
      {
         if (!localAddress.TryParse(localAddressStr, false))
         {
            result.append(Formatter::Format("ERROR: Unable to parse address {0}.\r\n", localAddressStr));
            return false;
         }
         else
            result.append(Formatter::Format("Local address is {0}.\r\n", localAddress.ToString()));
      }

      result.append(Formatter::Format("Trying to connect to host {0}...\r\n", server));
      

      // Get a list of endpoints corresponding to the server name.
      tcp::resolver resolver(io_service);
      tcp::resolver::query query(AnsiString(server), AnsiString(StringParser::IntToString(port)), tcp::resolver::query::numeric_service);
      boost::system::error_code errorResolve = boost::asio::error::host_not_found;
      tcp::resolver::iterator endpoint_iterator = resolver.resolve(query, errorResolve);
      tcp::resolver::iterator end;

      if (errorResolve || endpoint_iterator == end)
      {
         // Host was not found.
         String formattedString;
         formattedString.Format(_T("ERROR: The host name %s could not be resolved.\r\n"), server);
         
         result.append(formattedString);
         return false;
      }

      // Try each endpoint until we successfully establish a connection.
      tcp::socket socket(io_service);
      boost::system::error_code error = boost::asio::error::host_not_found;
      while (error && endpoint_iterator != end)
      {
         boost::asio::ip::address adr = (*endpoint_iterator).endpoint().address();

         String ipAddressString = adr.to_string();
         String formattedString;
         formattedString.Format(_T("Trying to connect to TCP/IP address %s on port %d.\r\n"), ipAddressString, port);

         result.append(formattedString);

         socket.close();

         IPAddress emptyAddr;
         bool any = emptyAddr.IsAny();

         if (!localAddress.IsAny())
         {
            socket.open(boost::asio::ip::tcp::v4());
            boost::system::error_code tempError;
            socket.bind(boost::asio::ip::tcp::endpoint(localAddress.GetAddress(), 0), tempError);

            if (tempError)
            {
               result.append(Formatter::Format("ERROR: Unable to bind to address {0}.\r\n", localAddress.ToString()));
               socket.close();
               return false;
            }
         }

         socket.connect(*endpoint_iterator++, error);
      }

      if (error)
      {
         // We were unable to connect.
         result.append(_T("ERROR: It was not possible to connect.\r\n"));
         return false;
      }

      // Read the response status line.
      boost::asio::streambuf response;
      boost::asio::read_until(socket, response, "\r\n");

      std::string s;
      std::istream is(&response);
      std::getline(is, s, '\r');
      result.append(Formatter::Format("Received: {0}.\r\n", String(s)));

      // Close the socket again.
      socket.close();

      result.append(_T("Connected successfully.\r\n"));
      return true;

   }
Example #11
0
   void 
   TCPServer::HandleAccept(shared_ptr<TCPConnection> pConnection,
      const boost::system::error_code& error)
   {
      if (error.value() == 995)
      {
         String sMessage;
         sMessage.Format(_T("TCP - AcceptEx failed. Error code: %d, Message: %s"), error.value(), String(error.message()));
         LOG_DEBUG(sMessage);

         /*
             995: The I/O operation has been aborted because of either a thread exit or an application request
             
             This happens when the servers are stopped. We shouldn't post any new accepts or do anything
             else in this situation.
        */

         return;
      }

      // Post another AcceptEx. We should always have outstanding unless the 
      // server is stopping, which we are taking care of above.
      StartAccept();

      if (!error)
      {
         boost::asio::ip::tcp::endpoint localEndpoint = pConnection->GetSocket().local_endpoint();
         boost::asio::ip::tcp::endpoint remoteEndpoint = pConnection->GetSocket().remote_endpoint();

         IPAddress localAddress (localEndpoint.address());
         IPAddress remoteAddress (remoteEndpoint.address());

         String sMessage = Formatter::Format("TCP - {0} connected to {1}:{2}.", remoteAddress.ToString(), localAddress.ToString(), port_);
         LOG_TCPIP(sMessage);

         shared_ptr<SecurityRange> securityRange = PersistentSecurityRange::ReadMatchingIP(remoteAddress);

         if (!securityRange)
         {
            LOG_TCPIP("TCP - Connection dropped - No matching IP range.");
            return;
         }


         bool allow = SessionManager::Instance()->GetAllow(sessionType_, securityRange);
        
         if (!allow)
         {
            // Session creation failed. May not be matching IP range, or enough connections have been created.
            String message;
            message.Format(_T("Client connection from %s was not accepted. Blocked either by IP range or by connection limit."), String(remoteAddress.ToString()));
            LOG_DEBUG(message);

            // Give option to hold connection for anti-pounding & hopefully minimize DoS
            // NOTE: We really need max connections per IP as well
            int iBlockedIPHoldSeconds = IniFileSettings::Instance()->GetBlockedIPHoldSeconds();

            if (iBlockedIPHoldSeconds > 0)
            {
               Sleep(iBlockedIPHoldSeconds * 1000);
               message.Format(_T("Held connection from %s for %i seconds before dropping."), String(remoteAddress.ToString()), iBlockedIPHoldSeconds);
               LOG_DEBUG(message);
            }

            return;
         }

         if (!FireOnAcceptEvent(remoteAddress, localEndpoint.port()))
            return;

         pConnection->SetSecurityRange(securityRange);
         pConnection->Start();
      }
      else
      {
         if (error.value() == 10009 || error.value() == 995)
         {
            // Not really errors..
            return;
         }

         // The outstanding accept-ex failed. This may or may not be an error. Default to being positive.
         String sMessage;
         sMessage.Format(_T("TCP - AcceptEx failed. Error code: %d, Message: %s"), error.value(), String(error.message()));
         LOG_TCPIP(sMessage);
      }
   }
Example #12
0
void CGUL::Network::HTTPRequest::ConnectSSL(const IPAddress& ip, int port)
{
    host = ip.ToString();
    sock->ConnectSSL(ip, port);
}
   void MessageUtilitiesTester::Test()
   {
      std::list<String> headerLines;
      headerLines.push_back("from host.edu (host.edu [1.2.3.4]) by mail.host.edu (8.8.5) id 004A21; Tue, Mar 18 1997 14:36:17 -0800 (PST)\r\n");
      headerLines.push_back("from someone.google (someone.google [1.1.1.1]) by mail.host.edu (8.8.5) id 004A21; Tue, Mar 18 1997 14:36:17 -0800 (PST)\r\n");

      String hostName;
      IPAddress address;

      bool result = MessageUtilities::RetrieveOriginatingAddress(headerLines, hostName, address);
      
      if (result == false)
         throw;

      if (hostName != _T("host.edu"))
         throw;

      if (address.ToString() != "1.2.3.4")
         throw;

      if (address.IsAny())
         throw;

      // If the message
      headerLines.clear();
      headerLines.push_back("by 10.103.12.12 with SMTP id p12cs158601mui; Mon, 14 Dec 2009 08:53:48 -0800 (PST)");
      headerLines.push_back("by 10.224.63.1 with SMTP id z1mr3063080qah.314.1260809627613; Mon, 14 Dec 2009 08:53:47 -0800 (PST)");
      headerLines.push_back("from e113.en25.com (e113.en25.com [209.167.231.113]) by mx.google.com with ESMTP id 9si6782547iwn.6.2009.12.14.08.53.46; Mon, 14 Dec 2009 08:53:47 -0800 (PST)");

      result = MessageUtilities::RetrieveOriginatingAddress(headerLines, hostName, address);

      if (result == false)
         throw;

      if (hostName != _T("e113.en25.com"))
         throw;

      if (address.ToString() != "209.167.231.113")
         throw;


      if (address.IsAny())
         throw;


      // We are unable to parse this because the IP address isn't within brackets ([]).
      headerLines.clear();
      headerLines.push_back("(qmail 25533 invoked from network); 19 Jan 2010 20:06:21 +0100");
      headerLines.push_back("from ded943.maximumasp.com (HELO mail.hmailserver.com) (216.128.26.134)");

      result = MessageUtilities::RetrieveOriginatingAddress(headerLines, hostName, address);

      if (result == true)
         throw;

      if (hostName != _T(""))
         throw;

      if (address.ToString() != "0.0.0.0")
         throw;

      if (!address.IsAny())
         throw;
   }
Example #14
0
bool
TestConnect::PerformTest(ConnectionSecurity connection_security, const String  &localAddressStr, const String &server, int port, String &result)
{
    std::shared_ptr<IOService> io_service_wrapper = Application::Instance()->GetIOService();

    IPAddress localAddress;
    if (!localAddressStr.IsEmpty())
    {
        if (!localAddress.TryParse(localAddressStr, false))
        {
            result.append(Formatter::Format("ERROR: Unable to parse address {0}.\r\n", localAddressStr));
            return false;
        }
        else
            result.append(Formatter::Format("Local address is {0}.\r\n", localAddress.ToString()));
    }

    result.append(Formatter::Format("Trying to connect to host {0}...\r\n", server));


    // Get a list of endpoints corresponding to the server name.
    tcp::resolver resolver(io_service_wrapper->GetIOService());
    tcp::resolver::query query(AnsiString(server), AnsiString(StringParser::IntToString(port)), tcp::resolver::query::numeric_service);
    boost::system::error_code errorResolve = boost::asio::error::host_not_found;
    tcp::resolver::iterator endpoint_iterator = resolver.resolve(query, errorResolve);
    tcp::resolver::iterator end;

    if (errorResolve || endpoint_iterator == end)
    {
        // Host was not found.
        String formattedString;
        formattedString.Format(_T("ERROR: The host name %s could not be resolved.\r\n"), server.c_str());

        result.append(formattedString);
        return false;
    }

    String last_error_message;

    // Try each endpoint until we successfully establish a connection.
    boost::system::error_code error = boost::asio::error::host_not_found;
    while (error && endpoint_iterator != end)
    {
        boost::asio::ip::address adr = (*endpoint_iterator).endpoint().address();

        String ipAddressString = adr.to_string();
        String formattedString;
        formattedString.Format(_T("Trying to connect to TCP/IP address %s on port %d.\r\n"), ipAddressString.c_str(), port);
        result.append(formattedString);


        std::shared_ptr<Event> disconnectEvent = std::shared_ptr<Event>(new Event());

        std::shared_ptr<TestConnectionResult> connection_result = std::make_shared<TestConnectionResult>();

        std::shared_ptr<TestConnection> connection = std::make_shared<TestConnection>(connection_security, io_service_wrapper->GetIOService(), io_service_wrapper->GetClientContext(), disconnectEvent, server, connection_result);
        if (connection->Connect(ipAddressString, port, localAddress))
        {
            connection.reset();

            disconnectEvent->Wait();

            if (connection_result->GetConnectedSuccesfully())
            {
                result.append(_T("Connected successfully.\r\n"));

                if (connection_security == CSSSL)
                {
                    if (connection_result->GetHandshakeCompletedSuccesfully())
                    {
                        result.append(_T("SSL/TLS handshake completed successfully.\r\n"));
                        return true;
                    }
                    else
                    {
                        result.append(_T("ERROR: Handshake failed.\r\n"));
                        return false;
                    }
                }
                else
                {
                    return true;
                }
            }
            else
            {
                result.append(Formatter::Format("ERROR: It was not possible to connect. Error: {0}.\r\n", connection_result->GetErrorMessage()));
            }
        }

        endpoint_iterator++;
    }

    // We were unable to connect.
    result.append(_T("ERROR: Failed to connect to all servers.\r\n"));
    return false;
}
Example #15
0
/** @brief Connects to a server on a given ip and port.
 *  @param ip The IP address to connect to.
 *  @param port The port number.
 */
void Jatta::Network::SocketTCP::Connect(const IPAddress& ip, unsigned short port)
{
    // Check that the IP is valid
    if (!ip.IsValid())
    {
        throw NetworkException(NetworkExceptionCode::FAILED_CONNECT, NetworkExceptionReason::ADDRESS_INVALID);
    }

    // Create a hints variable used to determine the connection configuration.
    struct addrinfo hints;
    memset(&hints, 0, sizeof(addrinfo));

    // Check if the IP is an IPv4 or IPv6.
    if (ip.GetType() == IPAddressType::IPV4)
    {
        // Use IPv4.
        hints.ai_family = AF_INET;
    }
    else
    {
        // Use IPv6.
        hints.ai_family = AF_INET6;
    }

    // We're setting up a TCP/IP connection, which is a STREAM socket.
    hints.ai_socktype = SOCK_STREAM;

    // Convert the port into a string.
    char portString[6];
#   ifdef MSVC
    sprintf_s(portString, "%d", port);
#   else
    sprintf(portString, "%d", port);
#   endif

    // Get the address info using the hints.
    addrinfo* result;
    if (getaddrinfo(ip.ToString().GetCString(), portString, &hints, &result) != 0)
    {
        throw NetworkException(NetworkExceptionCode::FAILED_CONNECT, NetworkExceptionReason::NO_NETWORK_INTERFACE);
    }

    // Create the socket.  Because our hints are so strict, we don't have to worry about looping
    // through the linked list.  We should be able to trust that the first result is what we want.
    sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    if (sock == INVALID_SOCKET)
    {
        freeaddrinfo(result);
        throw NetworkException(NetworkExceptionCode::FAILED_CONNECT, NetworkExceptionReason::FAILED_CREATE_SOCKET);
    }

    // Make the connection.
    if (::connect(sock, result->ai_addr, result->ai_addrlen) == SOCKET_ERROR)
    {
        freeaddrinfo(result);
        Close();
        throw NetworkException(NetworkExceptionCode::FAILED_CONNECT, NetworkExceptionReason::FAILED_CONNECT_CALL);
    }

    // Make a non-blocking socket.
    if (!MakeNonBlocking())
    {
        freeaddrinfo(result);
        Close();
        throw NetworkException(NetworkExceptionCode::FAILED_CONNECT, NetworkExceptionReason::FAILED_NONBLOCKING);
    }

    // Turn off the Nagle Algorithm to increase speed.
    if (!MakeNoDelay())
    {
        freeaddrinfo(result);
        Close();
        throw NetworkException(NetworkExceptionCode::FAILED_CONNECT, NetworkExceptionReason::FAILED_NO_DELAY);
    }

    // Free up the address info linked list.
    freeaddrinfo(result);
}
   bool
   SpamProtection::PerformGreyListing(std::shared_ptr<Message> message, const std::set<std::shared_ptr<SpamTestResult> > &spamTestResults, const String &toAddress, const IPAddress &ipaddress)
   {
      if (!Configuration::Instance()->GetAntiSpamConfiguration().GetUseGreyListing())
      {
         // The sender is either local, or grey listing is not enabled. We should
         // not do grey list checks in these cases.
         return true;
      }

      // Check if we should use grey listing for the recipient domain.
      String sRecipientDomain = StringParser::ExtractDomain(toAddress);
      std::shared_ptr<const Domain> pDomain = CacheContainer::Instance()->GetDomain(sRecipientDomain);         

      if (pDomain && !pDomain->GetASUseGreyListing())
      {
         // Grey listing not enabled in domain. Skip it.
         return true;
      }


      // Check if the SPF test has succeeded. If so, maybe we should not do
      if (Configuration::Instance()->GetAntiSpamConfiguration().GetBypassGreyListingOnSPFSuccess())
      {
         for(std::shared_ptr<SpamTestResult> testResult : spamTestResults)
         {
            if (testResult->GetTestName() == SpamTestSPF::GetTestName())
            {
               if (testResult->GetResult() == SpamTestResult::Pass)
               {
                  // We should not run grey listing since the SPF test has passed
                  LOG_DEBUG("SPF passed, skipping greylisting.");
                  return true;
               }
            }
         }
      }

      // Check if the mail is coming from the domain A record or MX record. If so, bypass grey listing.
      if (Configuration::Instance()->GetAntiSpamConfiguration().GetBypassGreyListingOnMailFromMX())
      {
         String senderDomain = StringParser::ExtractDomain(message->GetFromAddress());
         
         if (senderDomain.GetLength() > 0)
         {
            std::vector<String> found_ip_addresses;
               
            DNSResolver resolver;
            resolver.GetARecords(senderDomain, found_ip_addresses);

            std::vector<HostNameAndIpAddress> host_name_with_addresses;
            resolver.GetEmailServers(senderDomain, host_name_with_addresses);

            for(HostNameAndIpAddress host_and_ip : host_name_with_addresses)
               found_ip_addresses.push_back(host_and_ip.GetIpAddress());

            String actualFromAddress = ipaddress.ToString();
            for(String found_ip_address : found_ip_addresses)
            {
               if (found_ip_address.CompareNoCase(actualFromAddress) == 0)
               {
                  // The message is coming from either an A record or a MX record. Skip greylisting.
                  LOG_DEBUG("Mail coming from A or MX record. Skipping grey listing.");
                  return true;
               }
            }
         }
      }

      // Grey listing is enabled, and there's no reason to skip it. Go ahead!
      if (!GreyListingAllowSend(message->GetFromAddress(), toAddress, ipaddress))
         return false;

      return true; 
   }