Пример #1
0
   void 
   TCPConnection::AsyncHandshakeCompleted(const boost::system::error_code& error)
   {
      handshake_in_progress_ = false;

      if (!error)
      {
         is_ssl_ = true;

         // Send welcome message to client.
         auto cipher_info = GetCipherInfo();

         String sMessage;
         sMessage.Format(_T("TCPConnection - TLS/SSL handshake completed. Session Id: %d, Remote IP: %s, Version: %s, Cipher: %s, Bits: %d"), session_id_, SafeGetIPAddress().c_str(), String(cipher_info.GetVersion()).c_str(), String(cipher_info.GetName()).c_str(), cipher_info.GetBits());
         LOG_TCPIP(sMessage);
         
         receive_buffer_.consume(receive_buffer_.size());

         OnHandshakeCompleted();
      }
      else
      {
         HandshakeFailed_(error);
      }

      operation_queue_.Pop(IOOperation::BCTHandshake);
      ProcessOperationQueue_(0);

   }
Пример #2
0
   void
   TCPConnection::StartAsyncConnect_(const String &ip_adress, int port)
   {
      IPAddress adress;
      adress.TryParse(ip_adress, true);

      tcp::endpoint ep;
      ep.address(adress.GetAddress());
      ep.port(port);

      //// Check that we don't try to connect to a port we're listening on. Doing
      //// that could start evil loops.
      //tcp::endpoint endpoint = *endpoint_iterator;

      if (LocalIPAddresses::Instance()->IsLocalPort(ep.address(), remote_port_))
      {
         String sMessage; 
            sMessage.Format(_T("Could not connect to %s on port %d since this would mean connecting to myself."), remote_ip_address_.c_str(), remote_port_);

         OnCouldNotConnect(sMessage);

         LOG_TCPIP(_T("TCPConnection - ") + sMessage);

         return;
      }

      // Attempt a connection to the first endpoint in the list. Each endpoint
      // will be tried until we successfully establish a connection.
      socket_.async_connect(ep,
               std::bind(&TCPConnection::AsyncConnectCompleted, shared_from_this(), std::placeholders::_1));

   }
Пример #3
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;
   }
Пример #4
0
   void
   TCPConnection::HandshakeFailed_(const boost::system::error_code& error)
   {
      // The SSL handshake failed. This may happen for example if the user who has connected
      // to the TCP/IP port disconnects immediately without sending any data.
      String sMessage;
      sMessage.Format(_T("TCPConnection - TLS/SSL handshake failed. Session Id: %d, Remote IP: %s, Error code: %d, Message: %s"), session_id_, SafeGetIPAddress().c_str(), error.value(), String(error.message()).c_str());
      LOG_TCPIP(sMessage);

      OnHandshakeFailed();
   }
Пример #5
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);
      }
   }
Пример #6
0
   bool
   DNSResolver::Resolve_(const String &sSearchFor, std::vector<String> &vecFoundNames, WORD wType, int iRecursion)
   {
      if (iRecursion > 10)
      {
         String sMessage = Formatter::Format("Too many recursions during query. Query: {0}, Type: {1}", sSearchFor, wType);
         ErrorManager::Instance()->ReportError(ErrorManager::Low, 4401, "DNSResolver::Resolve_", sMessage);

         return false;
      }

      PDNS_RECORD pDnsRecord = NULL;
      PIP4_ARRAY pSrvList = NULL;

      DWORD fOptions = DNS_QUERY_STANDARD;
      
      DNS_STATUS nDnsStatus = DnsQuery(sSearchFor, wType, fOptions, NULL, &pDnsRecord, NULL);

      PDNS_RECORD pDnsRecordsToDelete = pDnsRecord;

      if (nDnsStatus != 0)
      {
         if (pDnsRecordsToDelete)
            _FreeDNSRecord(pDnsRecordsToDelete);

         bool bDNSError = IsDNSError_(nDnsStatus);

         if (bDNSError)
         {
            String sMessage;
            sMessage.Format(_T("DNS - Query failure. Query: %s, Type: %d, DnsQuery return value: %d."), sSearchFor.c_str(), wType, nDnsStatus);
            LOG_TCPIP(sMessage);
            return false;
         }

         return true;
      }

      std::vector<DnsRecordWithPreference> foundDnsRecordsWithPreference;

      do
      {
         switch (pDnsRecord->wType)
         {
            case DNS_TYPE_A:
            {
               SOCKADDR_IN addr;
               memset(&addr, 0, sizeof addr);

               addr.sin_family = AF_INET;
               addr.sin_addr = *((in_addr*)&(pDnsRecord->Data.AAAA.Ip6Address));

               char buf[128];
               DWORD bufSize = sizeof(buf);

               if (WSAAddressToStringA((sockaddr*)&addr, sizeof addr, NULL, buf, &bufSize) == 0)
               {
                  DnsRecordWithPreference rec(0, buf);
                  foundDnsRecordsWithPreference.push_back(rec);
               }
               
               break;
            }
            case DNS_TYPE_AAAA:
            {
               SOCKADDR_IN6 addr;
               memset(&addr, 0, sizeof addr);

               addr.sin6_family = AF_INET6;
               addr.sin6_addr = *((in_addr6*)&(pDnsRecord->Data.AAAA.Ip6Address));

               char buf[128];
               DWORD bufSize = sizeof(buf);

               if (WSAAddressToStringA((sockaddr*)&addr, sizeof addr, NULL, buf, &bufSize) == 0)
               {
                  DnsRecordWithPreference rec(0, buf);
                  foundDnsRecordsWithPreference.push_back(rec);
               }
               
               break;
            }
            case DNS_TYPE_CNAME:
            {
               String sDomainName = pDnsRecord->Data.CNAME.pNameHost;
               if (!Resolve_(sDomainName, vecFoundNames, wType, iRecursion+1))
                  return false;

               break;
            }
            case DNS_TYPE_MX: 
            {
               String sName = pDnsRecord->pName;
               bool bNameMatches = (sName.CompareNoCase(sSearchFor) == 0);

               if (pDnsRecord->Flags.S.Section == DNSREC_ANSWER && bNameMatches)
               {
                  DnsRecordWithPreference rec(pDnsRecord->Data.MX.wPreference, pDnsRecord->Data.MX.pNameExchange);
                  foundDnsRecordsWithPreference.push_back(rec);
               }

               break;
            }
         case DNS_TYPE_TEXT: 
            {
               AnsiString retVal;

               for (u_int i = 0; i < pDnsRecord->Data.TXT.dwStringCount; i++)
                  retVal += pDnsRecord->Data.TXT.pStringArray[i];
               
               DnsRecordWithPreference rec (0, retVal);
               foundDnsRecordsWithPreference.push_back(rec);

               break;
            }
         case DNS_TYPE_PTR: 
            {
               AnsiString retVal;
               retVal = pDnsRecord->Data.PTR.pNameHost;

               DnsRecordWithPreference rec(0, retVal);
               foundDnsRecordsWithPreference.push_back(rec);
               break;
            }
            default:
            {
               ErrorManager::Instance()->ReportError(ErrorManager::Medium, 5036, "DNSResolver::Resolve_", Formatter::Format("Queried for {0} but received type {1}", wType, pDnsRecord->wType));
               break;
            }
         }

         pDnsRecord = pDnsRecord->pNext;
      }
      while (pDnsRecord != nullptr);

      std::sort(foundDnsRecordsWithPreference.begin(), foundDnsRecordsWithPreference.end(), SortDnsRecordWithPreference);

      for (DnsRecordWithPreference item : foundDnsRecordsWithPreference)
      {
         vecFoundNames.push_back(item.Value);
      }

      _FreeDNSRecord(pDnsRecordsToDelete);
      pDnsRecordsToDelete = 0;

      return true;
   }
Пример #7
0
   bool
   DNSResolver::GetEmailServers(const String &sDomainName, std::vector<HostNameAndIpAddress> &saFoundNames )
   {
      String message = Formatter::Format("DNS MX lookup: {0}", sDomainName);
      LOG_TCPIP(message);

      std::vector<String> vecFoundMXRecords;

      if (!Resolve_(sDomainName, vecFoundMXRecords, DNS_TYPE_MX, 0))
      {
         String logMessage;
            logMessage.Format(_T("Failed to resolve email servers (MX lookup). Domain name: %s."), sDomainName.c_str());
         LOG_DEBUG(logMessage);

         return false;
      }

      if (vecFoundMXRecords.empty())
      {
         /* RFC 2821:
            If no MX records are found, but an A RR is found, the A RR is treated as
            if it was associated with an implicit MX RR, with a preference of 0,
            pointing to that host.  If one or more MX RRs are found for a given
            name, SMTP systems MUST NOT utilize any A RRs associated with that
            name unless they are located using the MX RRs;
            (implemented here)
         */

         std::vector<String> a_records;
         if (!GetIpAddresses(sDomainName, a_records))
         {
            String logMessage;
               logMessage.Format(_T("Failed to resolve email servers (A lookup). Domain name: %s."), sDomainName.c_str());
            LOG_DEBUG(logMessage);

            return false;
         }
		 
		    for(String record : a_records)         
		    {
		 	   HostNameAndIpAddress hostAndAddress;
            hostAndAddress.SetHostName(sDomainName);
            hostAndAddress.SetIpAddress(record);

            saFoundNames.push_back(hostAndAddress);
         }
      }
      else
      {
         // We've been able to find host names in the MX records. We should
         // now translate them to IP addresses. Some host names may result
         // in several IP addreses.
         auto iterDomain = vecFoundMXRecords.begin();

         bool dnsSuccess = false;
         for(String domain : vecFoundMXRecords)
         {
            // Resolve to domain name to IP address and put it in the list.
            size_t iCountBefore = saFoundNames.size();

            std::vector<String> a_records;
            if (!GetIpAddresses(domain, a_records))
               continue;

            dnsSuccess = true;
            
            if (saFoundNames.size() == iCountBefore)
            {
               // No mx records were found for this host name. Check if the host
               // name is actually an IP address? It shouldn't be but....

               if (StringParser::IsValidIPAddress(domain))
               {
                  // Okay, this is an invalid MX record. The MX record should always contain 
                  // a host name but in this case it appears an IP address. We'll be kind to
                  // the domain owner and still deliver the email to him.
                  a_records.push_back(domain);
               }
            }

            for(String record : a_records)
            {
               HostNameAndIpAddress hostAndAddress;
               hostAndAddress.SetHostName(domain);
               hostAndAddress.SetIpAddress(record);

               saFoundNames.push_back(hostAndAddress);
            }
         }

         if (!dnsSuccess)
         {
            // All dns queries failed.
            String logMessage;
               logMessage.Format(_T("Failed to resolve email servers (A lookup). Domain name: %s."), sDomainName.c_str());
            LOG_DEBUG(logMessage);

            return false;
         }

      }

      String sLogMsg;
      sLogMsg.Format(_T("DNS - MX Result: %d IP addresses were found."), saFoundNames.size());

      LOG_TCPIP(sLogMsg);

            
      // Remove duplicate names.
      auto iter = saFoundNames.begin();
      std::set<String> duplicateCheck;

      while (iter != saFoundNames.end())
      {
         String name = (*iter).GetIpAddress();
         if (duplicateCheck.find(name) != duplicateCheck.end())
         {
            // We found a duplicate. Remove it.
            iter = saFoundNames.erase(iter);
         }
         else
         {
            // This is not a duplicate. Move to next.
            iter++;

            duplicateCheck.insert(name);
         }
      }

      return true;
   }