예제 #1
0
        /// <summary>
        /// Parses resource record from reply data.
        /// </summary>
        /// <param name="reply">DNS server reply data.</param>
        /// <param name="offset">Current offset in reply data.</param>
        /// <param name="rdLength">Resource record data length.</param>
        /// <param name="ttl">Time to live in seconds.</param>
        public static DNS_rr_HINFO Parse(byte[] reply, ref int offset, int rdLength, int ttl)
        {
            /* RFC 1035 3.3.2. HINFO RDATA format
             *
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             *          /                      CPU                      /
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             *          /                       OS                      /
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             *
             *          CPU     A <character-string> which specifies the CPU type.
             *
             *          OS      A <character-string> which specifies the operating
             *                          system type.
             *
             *                          Standard values for CPU and OS can be found in [RFC-1010].
             *
             */

            // CPU
            string cpu = Dns_Client.ReadCharacterString(reply, ref offset);

            // OS
            string os = Dns_Client.ReadCharacterString(reply, ref offset);

            return(new DNS_rr_HINFO(cpu, os, ttl));
        }
예제 #2
0
 public bool IsValidMXRecord(string _domain)
 {
     try
     {
         Dns_Client.DnsServers  = new string[] { "8.8.8.8" };
         Dns_Client.UseDnsCache = true;
         using (Dns_Client dns = new Dns_Client())
         {
             DnsServerResponse reponse = null;
             reponse = dns.Query(_domain, LumiSoft.Net.DNS.DNS_QType.MX);
             if (((LumiSoft.Net.DNS.DNS_rr_MX)reponse.Answers[0]).Host != null)
             {
                 return(true);
             }
             else
             {
                 return(false);
             }
         }
     }
     catch (Exception ex)
     {
         return(false);
     }
 }
예제 #3
0
        /// <summary>
        /// Cleans up any resources being used.
        /// </summary>
        public void Dispose()
        {
            if (m_IsDisposed)
            {
                return;
            }
            try{
                if (m_IsRunning)
                {
                    Stop();
                }
            }
            catch {
            }
            m_IsDisposed = true;

            // Release events.
            this.Error            = null;
            this.SessionCompleted = null;

            m_pQueues     = null;
            m_pSmartHosts = null;

            m_pDsnClient.Dispose();
            m_pDsnClient = null;
        }
예제 #4
0
        /// <summary>
        /// Parses resource record from reply data.
        /// </summary>
        /// <param name="name">DNS domain name that owns a resource record.</param>
        /// <param name="reply">DNS server reply data.</param>
        /// <param name="offset">Current offset in reply data.</param>
        /// <param name="rdLength">Resource record data length.</param>
        /// <param name="ttl">Time to live in seconds.</param>
        public static DNS_rr_TXT Parse(string name, byte[] reply, ref int offset, int rdLength, int ttl)
        {
            // TXT RR

            string text = Dns_Client.ReadCharacterString(reply, ref offset);

            return(new DNS_rr_TXT(name, text, ttl));
        }
예제 #5
0
        /// <summary>
        /// Start processing relay message.
        /// </summary>
        /// <param name="state">User data.</param>
        internal void Start(object state)
        {
            try{
                m_pSmtpClient = new SMTP_Client();
                m_pSmtpClient.LocalHostName = m_pLocalBindInfo.HostName;
                if (m_pServer.Logger != null)
                {
                    m_pSmtpClient.Logger           = new Logger();
                    m_pSmtpClient.Logger.WriteLog += new EventHandler <WriteLogEventArgs>(SmtpClient_WriteLog);
                }

                LogText("Starting to relay message '" + m_pRelayItem.MessageID + "' from '" + m_pRelayItem.From + "' to '" + m_pRelayItem.To + "'.");

                // Get all possible target hosts for active recipient.
                List <string> targetHosts = new List <string>();
                if (m_RelayMode == Relay_Mode.Dns)
                {
                    foreach (string host in SMTP_Client.GetDomainHosts(m_pRelayItem.To))
                    {
                        try{
                            foreach (IPAddress ip in Dns_Client.Resolve(host))
                            {
                                m_pTargets.Add(new Relay_Target(new IPEndPoint(ip, 25)));
                            }
                        }
                        catch {
                            // Failed to resolve host name.

                            LogText("Failed to resolve host '" + host + "' name.");
                        }
                    }
                }
                else if (m_RelayMode == Relay_Mode.SmartHost)
                {
                    foreach (Relay_SmartHost smartHost in m_pSmartHosts)
                    {
                        try{
                            m_pTargets.Add(new Relay_Target(new IPEndPoint(Dns_Client.Resolve(smartHost.Host)[0], smartHost.Port), smartHost.SslMode, smartHost.UserName, smartHost.Password));
                        }
                        catch {
                            // Failed to resolve smart host name.

                            LogText("Failed to resolve smart host '" + smartHost.Host + "' name.");
                        }
                    }
                }

                BeginConnect();
            }
            catch (Exception x) {
                Dispose(x);
            }
        }
예제 #6
0
        /// <summary>
        /// Parses resource record from reply data.
        /// </summary>
        /// <param name="name">DNS domain name that owns a resource record.</param>
        /// <param name="reply">DNS server reply data.</param>
        /// <param name="offset">Current offset in reply data.</param>
        /// <param name="rdLength">Resource record data length.</param>
        /// <param name="ttl">Time to live in seconds.</param>
        public static DNS_rr_PTR Parse(string name, byte[] reply, ref int offset, int rdLength, int ttl)
        {
            string domainName = "";

            if (Dns_Client.GetQName(reply, ref offset, ref domainName))
            {
                return(new DNS_rr_PTR(name, domainName, ttl));
            }
            else
            {
                throw new ArgumentException("Invalid PTR resource record data !");
            }
        }
예제 #7
0
        /// <summary>
        /// Parses resource record from reply data.
        /// </summary>
        /// <param name="name">DNS domain name that owns a resource record.</param>
        /// <param name="reply">DNS server reply data.</param>
        /// <param name="offset">Current offset in reply data.</param>
        /// <param name="rdLength">Resource record data length.</param>
        /// <param name="ttl">Time to live in seconds.</param>
        public static DNS_rr_CNAME Parse(string name, byte[] reply, ref int offset, int rdLength, int ttl)
        {
            string alias = "";

            if (Dns_Client.GetQName(reply, ref offset, ref alias))
            {
                return(new DNS_rr_CNAME(name, alias, ttl));
            }
            else
            {
                throw new ArgumentException("Invalid CNAME resource record data !");
            }
        }
예제 #8
0
        /// <summary>
        /// Parses resource record from reply data.
        /// </summary>
        /// <param name="name">DNS domain name that owns a resource record.</param>
        /// <param name="reply">DNS server reply data.</param>
        /// <param name="offset">Current offset in reply data.</param>
        /// <param name="rdLength">Resource record data length.</param>
        /// <param name="ttl">Time to live in seconds.</param>
        public static DNS_rr_NS Parse(string name, byte[] reply, ref int offset, int rdLength, int ttl)
        {
            // Name server name

            string server = "";

            if (Dns_Client.GetQName(reply, ref offset, ref server))
            {
                return(new DNS_rr_NS(name, server, ttl));
            }
            else
            {
                throw new ArgumentException("Invalid NS resource record data !");
            }
        }
        /// <summary>
        /// Parses resource record from reply data.
        /// </summary>
        /// <param name="name">DNS domain name that owns a resource record.</param>
        /// <param name="reply">DNS server reply data.</param>
        /// <param name="offset">Current offset in reply data.</param>
        /// <param name="rdLength">Resource record data length.</param>
        /// <param name="ttl">Time to live in seconds.</param>
        public static DNS_rr_SRV Parse(string name, byte[] reply, ref int offset, int rdLength, int ttl)
        {
            // Priority Weight Port Target

            // Priority
            int priority = reply[offset++] << 8 | reply[offset++];

            // Weight
            int weight = reply[offset++] << 8 | reply[offset++];

            // Port
            int port = reply[offset++] << 8 | reply[offset++];

            // Target
            string target = "";

            Dns_Client.GetQName(reply, ref offset, ref target);

            return(new DNS_rr_SRV(name, priority, weight, port, target, ttl));
        }
예제 #10
0
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="owner">Owner DNS client.</param>
        /// <param name="id">Transaction ID.</param>
        /// <param name="qtype">QTYPE value.</param>
        /// <param name="qname">QNAME value.</param>
        /// <param name="timeout">Timeout in milliseconds.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> or <b>qname</b> is null reference.</exception>
        internal DNS_ClientTransaction(Dns_Client owner, int id, DNS_QType qtype, string qname, int timeout)
        {
            if (owner == null)
            {
                throw new ArgumentNullException("owner");
            }
            if (qname == null)
            {
                throw new ArgumentNullException("qname");
            }

            m_pOwner = owner;
            m_ID     = id;
            m_QName  = qname;
            m_QType  = qtype;

            m_CreateTime             = DateTime.Now;
            m_pTimeoutTimer          = new TimerEx(timeout);
            m_pTimeoutTimer.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimeoutTimer_Elapsed);
        }
예제 #11
0
        /// <summary>
        /// Cleans up any resource being used.
        /// </summary>
        public void Dispose()
        {
            lock (m_pLock){
                if (this.State == DNS_ClientTransactionState.Disposed)
                {
                    return;
                }

                SetState(DNS_ClientTransactionState.Disposed);

                m_pTimeoutTimer.Dispose();
                m_pTimeoutTimer = null;

                m_pOwner = null;

                m_pResponse = null;

                this.StateChanged = null;
                this.Timeout      = null;
            }
        }
예제 #12
0
        /// <summary>
        /// Parses resource record from reply data.
        /// </summary>
        /// <param name="name">DNS domain name that owns a resource record.</param>
        /// <param name="reply">DNS server reply data.</param>
        /// <param name="offset">Current offset in reply data.</param>
        /// <param name="rdLength">Resource record data length.</param>
        /// <param name="ttl">Time to live in seconds.</param>
        public static DNS_rr_NAPTR Parse(string name, byte[] reply, ref int offset, int rdLength, int ttl)
        {
            /* RFC 3403.
             *  The packet format for the NAPTR record is as follows
             *                                 1  1  1  1  1  1
             *   0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |                     ORDER                     |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |                   PREFERENCE                  |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |  /                     FLAGS                     /
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |  /                   SERVICES                    /
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |  /                    REGEXP                     /
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |  /                  REPLACEMENT                  /
             |  /                                               /
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             */

            int order = reply[offset++] << 8 | reply[offset++];

            int preference = reply[offset++] << 8 | reply[offset++];

            string flags = Dns_Client.ReadCharacterString(reply, ref offset);

            string services = Dns_Client.ReadCharacterString(reply, ref offset);

            string regexp = Dns_Client.ReadCharacterString(reply, ref offset);

            string replacement = "";

            Dns_Client.GetQName(reply, ref offset, ref replacement);

            return(new DNS_rr_NAPTR(name, order, preference, flags, services, regexp, replacement, ttl));
        }
        /// <summary>
        /// Parses resource record from reply data.
        /// </summary>
        /// <param name="name">DNS domain name that owns a resource record.</param>
        /// <param name="reply">DNS server reply data.</param>
        /// <param name="offset">Current offset in reply data.</param>
        /// <param name="rdLength">Resource record data length.</param>
        /// <param name="ttl">Time to live in seconds.</param>
        public static DNS_rr_MX Parse(string name, byte[] reply, ref int offset, int rdLength, int ttl)
        {
            /* RFC 1035	3.3.9. MX RDATA format
             *
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |                  PREFERENCE                   |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |          /                   EXCHANGE                    /
             |          /                                               /
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |
             |          where:
             |
             |          PREFERENCE
             |                  A 16 bit integer which specifies the preference given to
             |                  this RR among others at the same owner.  Lower values
             |  are preferred.
             |
             |          EXCHANGE
             |              A <domain-name> which specifies a host willing to act as
             |  a mail exchange for the owner name.
             */

            int pref = reply[offset++] << 8 | reply[offset++];

            string server = "";

            if (Dns_Client.GetQName(reply, ref offset, ref server))
            {
                return(new DNS_rr_MX(name, pref, server, ttl));
            }
            else
            {
                throw new ArgumentException("Invalid MX resource record data !");
            }
        }
예제 #14
0
        //---- SMTP implementation ----//

        #region function SendMessageToServer

        private bool SendMessageToServer(string[] to, string reverse_path, Stream message)
        {
            // Get email from to string
            for (int i = 0; i < to.Length; i++)
            {
                to[i] = (new InfoControl.Net.Mail.Mime.eAddress(to[i])).Email;
            }

            ArrayList defectiveEmails = new ArrayList();

            Socket so = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            so.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 15000);
            BufferedSocket socket = new BufferedSocket(so);

            SocketLogger logger = null;

            if (m_LogCmds && this.SessionLog != null)
            {
                logger           = new SocketLogger(so, this.SessionLog);
                logger.SessionID = socket.GetHashCode().ToString();
                socket.Logger    = logger;
            }

            try{
                string reply         = "";
                bool   supports_SIZE = false;
                bool   supports_8BIT = false;
                bool   supports_BDAT = false;

                if (m_UseSmartHost)
                {
                    socket.Connect(new IPEndPoint(System.Net.Dns.Resolve(m_SmartHost).AddressList[0], m_Port));
                }
                else
                {
                    //---- Parse e-domain -------------------------------//
                    string domain = to[0];

                    // 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 (logger != null)
                        {
                            logger.AddTextEntry("Destination address '" + to[0] + "' is invalid, aborting !");
                        }
                        return(false);
                    }

                    //--- Get MX record -------------------------------------------//
                    Dns_Client dns = new Dns_Client();
                    Dns_Client.DnsServers = m_DnsServers;
                    DnsServerResponse dnsResponse = dns.Query(domain, QTYPE.MX);

                    switch (dnsResponse.ResponseCode)
                    {
                    case RCODE.NO_ERROR:
                        MX_Record[] mxRecords = dnsResponse.GetMXRecords();

                        // Try all available hosts by MX preference order, if can't connect specified host.
                        foreach (MX_Record mx in mxRecords)
                        {
                            try{
                                if (logger != null)
                                {
                                    logger.AddTextEntry("Connecting with mx record to: " + mx.Host);
                                }
                                socket.Connect(new IPEndPoint(System.Net.Dns.Resolve(mx.Host).AddressList[0], m_Port));
                                break;
                            }
                            catch {                                    // Just skip and let for to try next host.
                                if (logger != null)
                                {
                                    logger.AddTextEntry("Failed connect to: " + mx.Host);
                                }
                            }
                        }

                        /* 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 (mxRecords.Length == 0)
                        {
                            // Try to connect with A record
                            IPHostEntry ipEntry = null;
                            try{
                                if (logger != null)
                                {
                                    logger.AddTextEntry("No mx record, trying to get A record for: " + domain);
                                }
                                ipEntry = System.Net.Dns.Resolve(domain);
                            }
                            catch {
                                if (logger != null)
                                {
                                    logger.AddTextEntry("Invalid domain,no MX or A record: " + domain);
                                }
                                OnError(SMTP_ErrorType.InvalidEmailAddress, to, "email domain <" + domain + "> is invalid");

                                defectiveEmails.AddRange(to);

                                if (logger != null)
                                {
                                    logger.Flush();
                                }
                                return(false);
                            }

                            try{
                                if (logger != null)
                                {
                                    logger.AddTextEntry("Connecting with A record to:" + domain);
                                }
                                socket.Connect(new IPEndPoint(ipEntry.AddressList[0], m_Port));
                            }
                            catch {
                                if (logger != null)
                                {
                                    logger.AddTextEntry("Failed connect to:" + domain);
                                }
                            }
                        }
                        break;

                    case RCODE.NAME_ERROR:
                        if (logger != null)
                        {
                            logger.AddTextEntry("Invalid domain,no MX or A record: " + domain);
                        }
                        OnError(SMTP_ErrorType.InvalidEmailAddress, to, "email domain <" + domain + "> is invalid");

                        defectiveEmails.AddRange(to);

                        if (logger != null)
                        {
                            logger.Flush();
                        }
                        return(false);

                    case RCODE.SERVER_FAILURE:
                        if (logger != null)
                        {
                            logger.AddTextEntry("Dns server unvailable.");
                        }
                        OnError(SMTP_ErrorType.UnKnown, to, "Dns server unvailable.");

                        defectiveEmails.AddRange(to);

                        if (logger != null)
                        {
                            logger.Flush();
                        }
                        return(false);
                    }
                }

                if (!socket.Connected)
                {
                    OnError(SMTP_ErrorType.UnKnown, to, "Unable connect to server !");

                    if (logger != null)
                    {
                        logger.Flush();
                    }
                    return(false);
                }


                #region Get 220 reply from server

                /* NOTE: reply may be multiline
                 * 220 xx ready
                 *  or
                 * 220-someBull
                 * 200 xx
                 */

                // Server must reply 220 - Server OK
                reply = socket.ReadLine();
                if (!IsReplyCode("220", reply))
                {
                    OnError(SMTP_ErrorType.UnKnown, to, reply);
                    socket.SendLine("QUIT");

                    if (logger != null)
                    {
                        logger.Flush();
                    }
                    return(false);
                }
                else
                {
                    // 220-xxx<CRLF>
                    // 220 aa<CRLF> - means end
                    // reply isn't complete, get more
                    while (reply.IndexOf("220 ") == -1)
                    {
                        reply += socket.ReadLine();
                    }
                }

                #endregion


                #region cmd EHLO/HELO

                // Send greeting to server
                socket.SendLine("EHLO " + m_HostName);

                reply = socket.ReadLine();
                if (!IsReplyCode("250", reply))
                {
                    // EHLO failed, mayby server doesn't support it, try HELO
                    socket.SendLine("HELO " + m_HostName);
                    reply = socket.ReadLine();
                    if (!IsReplyCode("250", reply))
                    {
                        OnError(SMTP_ErrorType.UnKnown, to, reply);
                        socket.SendLine("QUIT");

                        defectiveEmails.AddRange(to);

                        if (logger != null)
                        {
                            logger.Flush();
                        }
                        return(false);
                    }
                    //	else{
                    //		supports_ESMTP = false;
                    //	}
                }
                else
                {
                    // 250-xxx<CRLF>
                    // 250 aa<CRLF> - means end
                    // reply isn't complete, get more
                    while (reply.IndexOf("250 ") == -1)
                    {
                        reply += socket.ReadLine();
                    }

                    // Check if SIZE argument is supported
                    if (reply.ToUpper().IndexOf("SIZE") > -1)
                    {
                        supports_SIZE = true;
                    }

                    // Check if 8BITMIME argument is supported
                    if (reply.ToUpper().IndexOf("8BITMIME") > -1)
                    {
                        supports_8BIT = true;
                    }

                    // Check if CHUNKING argument is supported
                    if (reply.ToUpper().IndexOf("CHUNKING") > -1)
                    {
                        supports_BDAT = true;
                    }
                }

                #endregion

                //*** All server today support 8-bit, just skip it.

                // If server doesn't support 8bit mime, check if message is 8bit.
                // If is we MAY NOT send this message or loss of data

                /*		if(!supports_8BIT){
                 *                      if(Is8BitMime(message)){
                 *                              OnError(SMTP_ErrorType.NotSupported,to,"Message is 8-Bit mime and server doesn't support it.");
                 *                              socket.SendLine("QUIT");
                 *
                 *                              if(logger != null){
                 *                                      logger.Flush();
                 *                              }
                 *                              return false;
                 *                      }
                 *              }*/


                #region cmd AUTH

                if (this.m_Username != null && m_Username.Length > 0 && m_Password != null && m_Password.Length > 0)
                {
                    if (reply.ToUpper().IndexOf("AUTH") > -1)
                    {
                        if (reply.ToUpper().IndexOf("LOGIN") > -1)
                        {
                            socket.SendLine("AUTH LOGIN");
                            reply = socket.ReadLine();
                            if (!IsReplyCode("334", reply))
                            {
                                OnError(SMTP_ErrorType.NotAuthenticated, to, "Failed to authenticate");
                                socket.SendLine("QUIT");

                                if (logger != null)
                                {
                                    logger.Flush();
                                }
                                return(false);
                            }

                            socket.SendLine(Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(m_Username.ToCharArray())));
                            reply = socket.ReadLine();
                            if (!IsReplyCode("334", reply))
                            {
                                OnError(SMTP_ErrorType.NotAuthenticated, to, "Failed to authenticate");
                                socket.SendLine("QUIT");

                                if (logger != null)
                                {
                                    logger.Flush();
                                }
                                return(false);
                            }

                            socket.SendLine(Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(m_Password.ToCharArray())));
                            reply = socket.ReadLine();
                            if (!IsReplyCode("235", reply))
                            {
                                OnError(SMTP_ErrorType.NotAuthenticated, to, "Failed to authenticate");
                                socket.SendLine("QUIT");

                                if (logger != null)
                                {
                                    logger.Flush();
                                }
                                return(false);
                            }
                        }
//						if(reply.ToUpper().IndexOf("CRAM-MD5") > -1)
//						{
//							socket.SendLine("AUTH CRAM-MD5");
//							reply = socket.ReadLine();
//							if (IsReplyCode("334",auth))
//							{
//								socket.SendLine(Convert.ToBase64String(Encoding.ASCII.GetBytes(m_Username.ToCharArray())));
//								socket.SendLine(Convert.ToBase64String(Encoding.ASCII.GetBytes(m_Password.ToCharArray())));
//							}
//						}
                    }
                    else
                    {
                        //server did not support AUTH
                    }
                }

                #endregion

                #region cmd MAIL
                // NOTE: Syntax:{MAIL FROM:<*****@*****.**> [SIZE=msgSize]<CRLF>}

                // Send Mail From
                if (supports_SIZE)
                {
                    socket.SendLine("MAIL FROM:<" + reverse_path + "> SIZE=" + (message.Length - message.Position));
                }
                else
                {
                    socket.SendLine("MAIL FROM:<" + reverse_path + ">");
                }

                reply = socket.ReadLine();
                if (!IsReplyCode("250", reply))
                {
                    // To Do: Check if size exceeded error:

                    OnError(SMTP_ErrorType.UnKnown, to, reply);
                    socket.SendLine("QUIT");

                    defectiveEmails.AddRange(to);

                    if (logger != null)
                    {
                        logger.Flush();
                    }
                    return(false);
                }

                #endregion

                #region cmd RCPT
                // NOTE: Syntax:{RCPT TO:<*****@*****.**><CRLF>}

                bool isAnyValidEmail = false;
                foreach (string rcpt in to)
                {
                    // Send Mail To
                    socket.SendLine("RCPT TO:<" + rcpt + ">");

                    reply = socket.ReadLine();
                    if (!IsReplyCode("250", reply))
                    {
                        // Is unknown user
                        if (IsReplyCode("550", reply))
                        {
                            OnError(SMTP_ErrorType.InvalidEmailAddress, new string[] { rcpt }, reply);
                        }
                        else
                        {
                            OnError(SMTP_ErrorType.UnKnown, new string[] { rcpt }, reply);
                        }

                        defectiveEmails.Add(rcpt);
                    }
                    else
                    {
                        isAnyValidEmail = true;
                    }
                }

                // If there isn't any valid email - quit.
                if (!isAnyValidEmail)
                {
                    socket.SendLine("QUIT");

                    if (logger != null)
                    {
                        logger.Flush();
                    }
                    return(false);
                }
                //---------------------------------------------//

                #endregion


                #region cmd DATA

                if (!(supports_BDAT && m_UseBDAT))
                {
                    // Notify Data Start
                    socket.SendLine("DATA");

                    reply = socket.ReadLine();
                    if (!IsReplyCode("354", reply))
                    {
                        OnError(SMTP_ErrorType.UnKnown, to, reply);
                        socket.SendLine("QUIT");

                        defectiveEmails.AddRange(to);

                        if (logger != null)
                        {
                            logger.Flush();
                        }
                        return(false);
                    }

                    //------- Do period handling -----------------------------------------//
                    // If line starts with '.', add additional '.'.(Read rfc for more info)
                    MemoryStream msgStrmPeriodOk = Core.DoPeriodHandling(message, true, false);
                    //--------------------------------------------------------------------//

                    // Check if message ends with <CRLF>, if not add it. -------//
                    if (msgStrmPeriodOk.Length >= 2)
                    {
                        byte[] byteEnd = new byte[2];
                        msgStrmPeriodOk.Position = msgStrmPeriodOk.Length - 2;
                        msgStrmPeriodOk.Read(byteEnd, 0, 2);

                        if (byteEnd[0] != (byte)'\r' && byteEnd[1] != (byte)'\n')
                        {
                            msgStrmPeriodOk.Write(new byte[] { (byte)'\r', (byte)'\n' }, 0, 2);
                        }
                    }
                    msgStrmPeriodOk.Position = 0;
                    //-----------------------------------------------------------//

                    //---- Send message --------------------------------------------//
                    long totalSent   = 0;
                    long totalLength = msgStrmPeriodOk.Length;
                    while (totalSent < totalLength)
                    {
                        byte[] dataBuf     = new byte[4000];
                        int    nCount      = msgStrmPeriodOk.Read(dataBuf, 0, dataBuf.Length);
                        int    countSended = socket.Send(dataBuf, 0, nCount, SocketFlags.None);
                        totalSent += countSended;

                        if (countSended != nCount)
                        {
                            msgStrmPeriodOk.Position = totalSent;
                        }

                        OnPartOfMessageIsSent(countSended, totalSent, totalLength);
                    }
                    //-------------------------------------------------------------//
                    msgStrmPeriodOk.Close();

                    // Notify End of Data
                    socket.SendLine(".");

                    reply = socket.ReadLine();
                    if (!IsReplyCode("250", reply))
                    {
                        OnError(SMTP_ErrorType.UnKnown, to, reply);
                        socket.SendLine("QUIT");

                        defectiveEmails.AddRange(to);

                        if (logger != null)
                        {
                            logger.Flush();
                        }
                        return(false);
                    }
                }

                #endregion

                #region cmd BDAT

                if (supports_BDAT && m_UseBDAT)
                {
                    socket.SendLine("BDAT " + (message.Length - message.Position) + " LAST");

                    //---- Send message --------------------------------------------//
                    long totalSent   = 0;
                    long totalLength = message.Length - message.Position;
                    while (totalSent < totalLength)
                    {
                        byte[] dataBuf     = new byte[4000];
                        int    nCount      = message.Read(dataBuf, 0, dataBuf.Length);
                        int    countSended = socket.Send(dataBuf, 0, nCount, SocketFlags.None);
                        totalSent += countSended;

                        if (countSended != nCount)
                        {
                            message.Position = totalSent;
                        }

                        OnPartOfMessageIsSent(countSended, totalSent, totalLength);
                    }
                    //-------------------------------------------------------------//

                    // Get store result
                    reply = socket.ReadLine();
                    if (!reply.StartsWith("250"))
                    {
                        OnError(SMTP_ErrorType.UnKnown, to, reply);
                        socket.SendLine("QUIT");

                        defectiveEmails.AddRange(to);

                        if (logger != null)
                        {
                            logger.Flush();
                        }
                        return(false);
                    }
                }

                #endregion

                #region cmd QUIT

                // Notify server - server can exit now
                socket.SendLine("QUIT");

                //	reply = socket.ReadLine();

                #endregion
            }
            catch (Exception x) {
                OnError(SMTP_ErrorType.UnKnown, to, x.Message);

                defectiveEmails.AddRange(to);

                if (logger != null)
                {
                    logger.Flush();
                }
                return(false);
            }
            finally{
                // Raise event
                OnSendJobCompleted(Thread.CurrentThread.GetHashCode().ToString(), to, defectiveEmails);
            }

            if (logger != null)
            {
                logger.Flush();
            }

            return(true);
        }
예제 #15
0
        /// <summary>
        /// Gets host name. If fails returns ip address.
        /// </summary>
        /// <param name="ip">IP address which to reverse lookup.</param>
        /// <returns>Returns host name of specified IP address.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>ip</b> is null.</exception>
        public static string GetHostName(IPAddress ip)
        {
            if (ip == null)
            {
                throw new ArgumentNullException("ip");
            }

            string retVal = ip.ToString();
            try
            {
                Dns_Client dns = new Dns_Client();
                DnsServerResponse response = dns.Query(ip.ToString(), QTYPE.PTR);
                if (response.ResponseCode == RCODE.NO_ERROR)
                {
                    DNS_rr_PTR[] ptrs = response.GetPTRRecords();
                    if (ptrs.Length > 0)
                    {
                        retVal = ptrs[0].DomainName;
                    }
                }
            }
            catch {}

            return retVal;
        }
예제 #16
0
        /// <summary>
        /// Parses resource record from reply data.
        /// </summary>
        /// <param name="name">DNS domain name that owns a resource record.</param>
        /// <param name="reply">DNS server reply data.</param>
        /// <param name="offset">Current offset in reply data.</param>
        /// <param name="rdLength">Resource record data length.</param>
        /// <param name="ttl">Time to live in seconds.</param>
        public static DNS_rr_SOA Parse(string name, byte[] reply, ref int offset, int rdLength, int ttl)
        {
            /* RFC 1035 3.3.13. SOA RDATA format
             *
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             *                  /                     MNAME                     /
             *                  /                                               /
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             *                  /                     RNAME                     /
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |                    SERIAL                     |
             |                                               |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |                    REFRESH                    |
             |                                               |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |                     RETRY                     |
             |                                               |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |                    EXPIRE                     |
             |                                               |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |                    MINIMUM                    |
             |                                               |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |
             |          where:
             |
             |          MNAME           The <domain-name> of the name server that was the
             |                                          original or primary source of data for this zone.
             |
             |          RNAME           A <domain-name> which specifies the mailbox of the
             |                                          person responsible for this zone.
             |
             |          SERIAL          The unsigned 32 bit version number of the original copy
             |                                          of the zone.  Zone transfers preserve this value.  This
             |                                          value wraps and should be compared using sequence space
             |                                          arithmetic.
             |
             |          REFRESH         A 32 bit time interval before the zone should be
             |                                          refreshed.
             |
             |          RETRY           A 32 bit time interval that should elapse before a
             |                                          failed refresh should be retried.
             |
             |          EXPIRE          A 32 bit time value that specifies the upper limit on
             |                                          the time interval that can elapse before the zone is no
             |                                          longer authoritative.
             |
             |          MINIMUM         The unsigned 32 bit minimum TTL field that should be
             |                                          exported with any RR from this zone.
             */

            //---- Parse record -------------------------------------------------------------//
            // MNAME
            string nameserver = "";

            Dns_Client.GetQName(reply, ref offset, ref nameserver);

            // RNAME
            string adminMailBox = "";

            Dns_Client.GetQName(reply, ref offset, ref adminMailBox);
            char[] adminMailBoxAr = adminMailBox.ToCharArray();
            for (int i = 0; i < adminMailBoxAr.Length; i++)
            {
                if (adminMailBoxAr[i] == '.')
                {
                    adminMailBoxAr[i] = '@';
                    break;
                }
            }
            adminMailBox = new string(adminMailBoxAr);

            // SERIAL
            long serial = reply[offset++] << 24 | reply[offset++] << 16 | reply[offset++] << 8 | reply[offset++];

            // REFRESH
            long refresh = reply[offset++] << 24 | reply[offset++] << 16 | reply[offset++] << 8 | reply[offset++];

            // RETRY
            long retry = reply[offset++] << 24 | reply[offset++] << 16 | reply[offset++] << 8 | reply[offset++];

            // EXPIRE
            long expire = reply[offset++] << 24 | reply[offset++] << 16 | reply[offset++] << 8 | reply[offset++];

            // MINIMUM
            long minimum = reply[offset++] << 24 | reply[offset++] << 16 | reply[offset++] << 8 | reply[offset++];

            //--------------------------------------------------------------------------------//

            return(new DNS_rr_SOA(name, nameserver, adminMailBox, serial, refresh, retry, expire, minimum, ttl));
        }
예제 #17
0
        /// <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;
        }
예제 #18
0
        /// <summary>
        /// Gets specified email domain possible connect points. Values are in priority descending order.
        /// </summary>
        /// <param name="domain">Email address or domain name.</param>
        /// <returns>Returns possible email server connection points.</returns>
        public IPAddress[] GetDestinations(string domain)
        {
            /* 
                1) Add MX records
                2) Add A records
            */

            // We have email address, just get domain from it.
            if (domain.IndexOf('@') > -1)
            {
                domain = domain.Substring(domain.IndexOf('@') + 1);
            }

            List<IPAddress> retVal = new List<IPAddress>();
            Dns_Client dns = new Dns_Client();
            Dns_Client.DnsServers = DnsServers;
            DnsServerResponse response = dns.Query(domain, QTYPE.MX);
            // Add MX            
            foreach (DNS_rr_MX mx in response.GetMXRecords())
            {
                try
                {
                    IPAddress[] ips = Dns.GetHostAddresses(mx.Host);
                    foreach (IPAddress ip in ips)
                    {
                        if (!retVal.Contains(ip))
                        {
                            retVal.Add(ip);
                        }
                    }
                }
                catch
                {
                    // Probably wrong MX record, no A reocrd for it, so we don't get IP. Just skip it.
                }
            }
            // Add A records only if no MX records.
            if (retVal.Count == 0)
            {
                response = dns.Query(domain, QTYPE.A);
                foreach (DNS_rr_A a in response.GetARecords())
                {
                    IPAddress ip = a.IP;
                    if (!retVal.Contains(ip))
                    {
                        retVal.Add(ip);
                    }
                }
            }

            return retVal.ToArray();
        }
예제 #19
0
        /// <summary>
        /// Default constructor.
        /// </summary>
        public SIP_Stack()
        {
            m_pTransportLayer = new SIP_TransportLayer(this);
            m_pTransactionLayer = new SIP_TransactionLayer(this);
            m_pNonceManager = new Auth_HttpDigest_NonceManager();
            m_pProxyServers = new List<SIP_Uri>();
            m_pRegistrations = new List<SIP_UA_Registration>();
            m_pCredentials = new List<NetworkCredential>();
            m_RegisterCallID = SIP_t_CallID.CreateCallID();

            m_pLogger = new Logger();

            m_pDnsClient = new Dns_Client();
        }
예제 #20
0
        /// <summary>
        /// Gets specified email domain SMTP hosts. Values are in descending priority order.
        /// </summary>
        /// <param name="domain">Domain name. This value can be email address too, then domain parsed automatically.</param>
        /// <returns>Returns specified email domain SMTP hosts.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>domain</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <exception cref="DNS_ClientException">Is raised when DNS query failure.</exception>
        public static string[] GetDomainHosts(string domain)
        {
            if (domain == null)
            {
                throw new ArgumentNullException("domain");
            }
            if (string.IsNullOrEmpty(domain))
            {
                throw new ArgumentException(
                    "Invalid argument 'domain' value, you need to specify domain value.");
            }

            // We have email address, parse domain.
            if (domain.IndexOf("@") > -1)
            {
                domain = domain.Substring(domain.IndexOf('@') + 1);
            }

            List<string> retVal = new List<string>();

            // Get MX records.
            Dns_Client dns = new Dns_Client();
            DnsServerResponse response = dns.Query(domain, QTYPE.MX);
            if (response.ResponseCode == RCODE.NO_ERROR)
            {
                foreach (DNS_rr_MX mx in response.GetMXRecords())
                {
                    // Block invalid MX records.
                    if (!string.IsNullOrEmpty(mx.Host))
                    {
                        retVal.Add(mx.Host);
                    }
                }
            }
            else
            {
                throw new DNS_ClientException(response.ResponseCode);
            }

            /* 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 (retVal.Count == 0)
            {
                retVal.Add(domain);
            }

            return retVal.ToArray();
        }
예제 #21
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 public Relay_Server()
 {
     m_pQueues     = new List <Relay_Queue>();
     m_pSmartHosts = new CircleCollection <Relay_SmartHost>();
     m_pDsnClient  = new Dns_Client();
 }