/// <summary> /// Connects to sepcified host. /// </summary> /// <param name="localEndpoint">Sets local endpoint. Pass null, to use default.</param> /// <param name="host">Host name or IP address.</param> /// <param name="port">Port where to connect.</param> /// <param name="ssl">Specifies if to connected via SSL. Default SMTP port is 25 and SSL port is 465.</param> public void Connect(IPEndPoint localEndpoint, string host, int port, bool ssl) { m_pSocket = new SocketEx(); if (localEndpoint != null) { m_pSocket.Bind(localEndpoint); } // Create logger if (SessionLog != null) { m_pLogger = new SocketLogger(m_pSocket.RawSocket, SessionLog); m_pLogger.SessionID = Guid.NewGuid().ToString(); m_pSocket.Logger = m_pLogger; } if (host.IndexOf("@") == -1) { m_pSocket.Connect(host, port, ssl); } else { //---- Parse e-domain -------------------------------// string domain = host; // eg. Ivx <*****@*****.**> if (domain.IndexOf("<") > -1 && domain.IndexOf(">") > -1) { domain = domain.Substring(domain.IndexOf("<") + 1, domain.IndexOf(">") - domain.IndexOf("<") - 1); } if (domain.IndexOf("@") > -1) { domain = domain.Substring(domain.LastIndexOf("@") + 1); } if (domain.Trim().Length == 0) { if (m_pLogger != null) { m_pLogger.AddTextEntry("Destination address '" + host + "' is invalid, aborting !"); } throw new Exception("Destination address '" + host + "' is invalid, aborting !"); } //--- Get MX record -------------------------------------------// Dns_Client dns = new Dns_Client(); Dns_Client.DnsServers = m_pDnsServers; DnsServerResponse dnsResponse = dns.Query(domain, QTYPE.MX); bool connected = false; switch (dnsResponse.ResponseCode) { case RCODE.NO_ERROR: DNS_rr_MX[] mxRecords = dnsResponse.GetMXRecords(); // Try all available hosts by MX preference order, if can't connect specified host. foreach (DNS_rr_MX mx in mxRecords) { try { if (m_pLogger != null) { m_pLogger.AddTextEntry("Connecting with mx record to: " + mx.Host); } m_pSocket.Connect(mx.Host, port, ssl); connected = true; break; } catch (Exception x) { // Just skip and let for to try next host. if (m_pLogger != null) { m_pLogger.AddTextEntry("Failed connect to: " + mx.Host + " error:" + x.Message); } } } // None of MX didn't connect if (mxRecords.Length > 0 && !connected) { throw new Exception("Destination email server is down"); } /* Rfc 2821 5 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 (!connected) { // Try to connect with A record IPAddress[] ipEntry = null; try { if (m_pLogger != null) { m_pLogger.AddTextEntry("No mx record, trying to get A record for: " + domain); } ipEntry = Dns_Client.Resolve(domain); } catch { if (m_pLogger != null) { m_pLogger.AddTextEntry("Invalid domain,no MX or A record: " + domain); } throw new Exception("Invalid domain,no MX or A record: " + domain); } try { if (m_pLogger != null) { m_pLogger.AddTextEntry("Connecting with A record to:" + domain); } m_pSocket.Connect(domain, port, ssl); } catch { if (m_pLogger != null) { m_pLogger.AddTextEntry("Failed connect to:" + domain); } throw new Exception("Destination email server is down"); } } break; case RCODE.NAME_ERROR: if (m_pLogger != null) { m_pLogger.AddTextEntry("Invalid domain,no MX or A record: " + domain); } throw new Exception("Invalid domain,no MX or A record: " + domain); case RCODE.SERVER_FAILURE: if (m_pLogger != null) { m_pLogger.AddTextEntry("Dns server unvailable."); } throw new Exception("Dns server unvailable."); } } /* * Notes: Greeting may be single or multiline response. * * Examples: * 220<SP>SMTP server ready<CRLF> * * 220-SMTP server ready<CRLF> * 220-Addtitional text<CRLF> * 220<SP>final row<CRLF> * */ // Read server response string responseLine = m_pSocket.ReadLine(1000); while (!responseLine.StartsWith("220 ")) { // If lisne won't start with 220, then its error response if (!responseLine.StartsWith("220")) { throw new Exception(responseLine); } responseLine = m_pSocket.ReadLine(1000); } m_Connected = true; }
/// <exception cref="System.IO.IOException"></exception> internal virtual void Ssn139() { Name calledName = new Name(Address.FirstCalledName(), 0x20, null); do { Socket = new SocketEx(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //TCPローカルポートは、毎回空いているものを使う。 //https://blogs.msdn.microsoft.com/dgorti/2005/09/18/only-one-usage-of-each-socket-address-protocolnetwork-addressport-is-normally-permitted/ Socket.Bind(new IPEndPoint(LocalAddr, 0)); Socket.Connect(new IPEndPoint(IPAddress.Parse(Address.GetHostAddress()), 139), SmbConstants.ConnTimeout); Socket.SoTimeOut = SmbConstants.SoTimeout; Out = Socket.GetOutputStream(); In = Socket.GetInputStream(); SessionServicePacket ssp = new SessionRequestPacket(calledName, NbtAddress.GetLocalName()); Out.Write(Sbuf, 0, ssp.WriteWireFormat(Sbuf, 0)); if (Readn(In, Sbuf, 0, 4) < 4) { try { //Socket.`Close` method deleted //Socket.Close(); Socket.Dispose(); } catch (IOException) { } throw new SmbException("EOF during NetBIOS session request"); } switch (Sbuf[0] & 0xFF) { case SessionServicePacket.PositiveSessionResponse: { if (Log.Level >= 4) { Log.WriteLine("session established ok with " + Address); } return; } case SessionServicePacket.NegativeSessionResponse: { int errorCode = In.Read() & 0xFF; switch (errorCode) { case NbtException.CalledNotPresent: case NbtException.NotListeningCalled: { //Socket.`Close` method deleted //Socket.Close(); Socket.Dispose(); break; } default: { Disconnect(true); throw new NbtException(NbtException.ErrSsnSrvc, errorCode); } } break; } case -1: { Disconnect(true); throw new NbtException(NbtException.ErrSsnSrvc, NbtException.ConnectionRefused); } default: { Disconnect(true); throw new NbtException(NbtException.ErrSsnSrvc, 0); } } }while ((calledName.name = Address.NextCalledName()) != null); throw new IOException("Failed to establish session with " + Address); }