Exemplo n.º 1
0
 // VRFY/EXPN
 private string _CmdVrfy(string cmdLine)
 {
     var id = _GetCommandId(cmdLine);
     _vrfyCount++;
     var parts = _ParseCmdLine(id, cmdLine);
     if (2 != parts.Count)
     {
         _errCount++;
         return String.Format("501 {0} needs argument", parts[0]);
     }
     if (!_CheckMailAddr(parts[1]))
     {
         _errCount++;
         return String.Format("553 Invalid address {0}", parts[1]);
     }
     _lastCmd = id;
     if (id == _CmdId.Vrfy)
         return "252 Cannot VRFY user; try RCPT to attempt delivery (or try finger)";
     return String.Format("250 {0}", parts[1]);
 }
Exemplo n.º 2
0
        // splits an SMTP command into command and argument(s)
        private List<string> _ParseCmdLine(_CmdId id, string cmdLine)
        {
            var parts = new List<string>();
            if (string.IsNullOrEmpty(cmdLine))
                return parts;
            try
            {
                var cmdStr = _cmdList[(int)id];

                var pos = cmdLine.IndexOf(cmdStr.Contains(':') ? ':' : ' ');
                if (-1 != pos)
                {
                    var cmd = _CleanupString(cmdLine.Substring(0, pos));
                    var arg = _CleanupString(cmdLine.Substring(pos + 1));
                    parts.Add(cmd.ToUpper());
                    parts.Add(arg);
                }
                else
                    parts.Add(_CleanupString(cmdLine).ToUpper());
            }
            catch
            {
                parts = new List<string>();
            }

            return parts;
        }
Exemplo n.º 3
0
 // RSET
 private string _CmdRset()
 {
     _ResetSession();
     _lastCmd = _CmdId.Rset;
     return "250 Reset Ok";
 }
Exemplo n.º 4
0
 // unknown/unsupported
 private string _CmdUnknown(string cmdLine)
 {
     _errCount++;
     _lastCmd = _CmdId.Invalid;
     return string.IsNullOrEmpty(cmdLine)
         ? "500 Command unrecognized"
         : string.Format("500 Command unrecognized ({0})", cmdLine);
 }
Exemplo n.º 5
0
 // QUIT
 private string _CmdQuit()
 {
     _lastCmd = _CmdId.Quit;
     return "221 Closing connection.";
 }
Exemplo n.º 6
0
        // RCPT TO:
        private string _CmdRcpt(string cmdLine)
        {
            if (string.IsNullOrEmpty(_mailFrom))
            {
                _errCount++;
                return "503 Need MAIL before RCPT";
            }
            var parts = _ParseCmdLine(_CmdId.RcptTo, cmdLine);
            if (2 != parts.Count)
            {
                _errCount++;
                return String.Format("501 {0} needs argument", parts[0]);
            }
            if (!_CheckMailAddr(parts[1]))
            {
                _errCount++;
                return String.Format("553 Invalid address {0}", parts[1]);
            }

            if (!_IsLocalDomain(_mailDom))
            {
                // relaying not allowed...
                _errCount++;
                return "530 Relaying not allowed for policy reasons";
            }
            if (!_IsLocalBox(_mailBox, _mailDom))
            {
                // unkown/invalid recipient
                _errCount++;
                return String.Format("553 Unknown email address {0}", parts[1]);
            }

            _rcptTo.Add(parts[1]);
            _lastCmd = _CmdId.RcptTo;
            return string.Format("250 {0}... Recipient ok", parts[1]);
        }
Exemplo n.º 7
0
 // MAIL FROM:
 private string _CmdMail(string cmdLine)
 {
     if (string.IsNullOrEmpty(_heloStr))
     {
         _errCount++;
         return "503 HELO/EHLO Command not issued";
     }
     if (!string.IsNullOrEmpty(_mailFrom))
     {
         _errCount++;
         return "503 Nested MAIL command";
     }
     var parts = _ParseCmdLine(_CmdId.MailFrom, cmdLine);
     if (2 != parts.Count)
     {
         _errCount++;
         return String.Format("501 {0} needs argument", parts[0]);
     }
     if (!_CheckMailAddr(parts[1]))
     {
         _errCount++;
         return String.Format("553 Invalid address {0}", parts[1]);
     }
     _mailFrom = parts[1];
     _lastCmd = _CmdId.MailFrom;
     return string.Format("250 {0}... Sender ok", parts[1]);
 }
Exemplo n.º 8
0
        // HELO/EHLO
        private string _CmdHelo(string cmdLine)
        {
            var id = _GetCommandId(cmdLine);
            var parts = _ParseCmdLine(id, cmdLine);
            if (2 != parts.Count)
            {
                _errCount++;
                return String.Format("501 {0} needs argument", parts[0]);
            }
            if (!string.IsNullOrEmpty(_heloStr))
            {
                _errCount++;
                return string.Format("503 you already sent {0} ...", parts[0]);
            }
            if (AppGlobals.CheckHelloFormat && !_CheckHelo(parts[1]))
            {
                _errCount++;
                return String.Format("501 Invalid {0}", parts[0]);
            }
            if (parts[1].ToLower().Equals("localhost") ||
                parts[1].ToLower().Equals(AppGlobals.HostName) ||
                parts[1].StartsWith("[127.") ||
                parts[1].Equals("[" + AppGlobals.ListenAddress + "]")
                )
            {
                _errCount++;
                return String.Format("501 spoofed {0}", parts[0]);
            }

            _heloStr = parts[1];
            _lastCmd = id;
            if (id == _CmdId.Helo)
                return String.Format("250 Hello {0} ([{1}]), nice to meet you.", parts[1], _clientIp);
            return String.Format("250 Hello {0} ([{1}]), nice to meet you.\r\n250-HELP\r\n250-VRFY\r\n250-EXPN\r\n250 NOOP", parts[1], _clientIp);
        }
Exemplo n.º 9
0
 // end of DATA (dot)
 private string _CmdDot()
 {
     _lastCmd = _CmdId.Noop;
     return "250 Queued mail for delivery";
 }
Exemplo n.º 10
0
 // DATA
 private string _CmdData()
 {
     if (_rcptTo.Count < 1)
     {
         _errCount++;
         return "471 Bad or missing RCPT command";
     }
     _lastCmd = _CmdId.Data;
     return "354 Start mail input; end with <CRLF>.<CRLF>";
 }
Exemplo n.º 11
0
        public void HandleSession()
        {
            var cmdLine = "?";
            var currCmd = _CmdId.Invalid;

            if (false == _initOk)
            {
                _CloseSession();
                return;
            }

            // sessions limit reached, reject session
            if (_sessCount > AppGlobals.MaxSessions)
            {
                _SendLine(_tempfailMsg);
                _CloseSession();
                return;
            }

            // if the remote IP isn't a private one
            if (!_IsPrivateIp(_clientIp))
            {
                // checks the incoming IP against whitelists, if listed skip blacklist checks
                var isDnsListed = _IsListed(_clientIp, AppGlobals.WhiteLists, "white");
                if (!isDnsListed)
                {
                    // check the IP against blacklists
                    isDnsListed = _IsListed(_clientIp, AppGlobals.BlackLists, "black");
                    if ((isDnsListed) && (!AppGlobals.StoreData))
                    {
                        // if blacklisted and NOT storing messages
                        _SendLine(string.Format(_dnsblMsg, _clientIp, _dnsListName));
                        _CloseSession();
                        return;
                    }
                }
            }

            // add a short delay before banner and check for early talker
            // see http://wiki.asrg.sp.am/wiki/Early_talker_detection
            _SleepDown(AppGlobals.BannerDelay);
            _earlyTalker = _IsEarlyTalker();
            if (_earlyTalker)
            {
                _SendLine(_etalkerMsg);
                _CloseSession();
                return;
            }

            // all ok, send out our banner
            var connOk = _SendLine(_CmdBanner());
            while ((null != cmdLine) && connOk)
            {
                string response;
                if (_lastCmd == _CmdId.Data)
                {
                    var mailMsg = _RecvData();
                    if (_timedOut)
                    {
                        // got a receive timeout during the DATA phase
                        _SendLine(_timeoutMsg);
                        _CloseSession();
                        return;
                    }
                    response = _CmdDot();
                    if (String.IsNullOrEmpty(mailMsg))
                        response = "422 Recipient mailbox exceeded quota limit.";
                    else
                    {
                        _StoreMailMsg(mailMsg);
                        if (AppGlobals.DoTempFail)
                        {
                            // emit a tempfail AFTER storing the mail DATA
                            _SendLine(_tempfailMsg);
                            _CloseSession();
                            return;
                        }
                    }
                    _ResetSession();
                }
                else
                {
                    // read an SMTP command line and deal with the command
                    cmdLine = _RecvLine();
                    if (null != cmdLine)
                    {
                        _LogCmdAndResp(_dirRx, cmdLine);
                        currCmd = _GetCommandId(cmdLine);
                        switch (currCmd)
                        {
                            case _CmdId.Helo: // HELO
                                response = _CmdHelo(cmdLine);
                                break;
                            case _CmdId.Ehlo: // EHLO
                                response = _CmdHelo(cmdLine);
                                break;
                            case _CmdId.MailFrom: // MAIL FROM:
                                response = _CmdMail(cmdLine);
                                break;
                            case _CmdId.RcptTo: // RCPT TO:
                                response = _CmdRcpt(cmdLine);
                                break;
                            case _CmdId.Data: // DATA
                                if ((AppGlobals.DoTempFail) && (!AppGlobals.StoreData))
                                {
                                    // emit a tempfail upon receiving the DATA command
                                    response = _tempfailMsg;
                                    cmdLine = null;
                                    _lastCmd = currCmd = _CmdId.Quit;
                                }
                                else
                                    response = _CmdData();
                                break;
                            case _CmdId.Rset: // RSET
                                response = _CmdRset();
                                break;
                            case _CmdId.Quit: // QUIT
                                response = _CmdQuit();
                                cmdLine = null; // force closing
                                break;
                            case _CmdId.Vrfy: // VRFY
                                response = _CmdVrfy(cmdLine);
                                break;
                            case _CmdId.Expn: // EXPN
                                response = _CmdVrfy(cmdLine);
                                break;
                            case _CmdId.Help: // HELP
                                response = _CmdHelp();
                                break;
                            case _CmdId.Noop: // NOOP
                                response = _CmdNoop(cmdLine);
                                break;
                            default: // unkown/unsupported
                                response = _CmdUnknown(cmdLine);
                                break;
                        }
                    }
                    else
                    {
                        // the read timed out (or we got an error), emit a message and drop the connection
                        response = _timeoutMsg;
                        currCmd = _CmdId.Quit;
                    }
                }

                // send response
                if ((_errCount > 0) && (_CmdId.Quit != currCmd))
                {
                    // tarpit a bad client, time increases with error count
                    _SleepDown(AppGlobals.ErrorDelay * _errCount);
                }
                else
                {
                    // add a short delay
                    _SleepDown(25);
                }

                // checks for early talkers
                _earlyTalker = _IsEarlyTalker();

                // send out the response
                connOk = _SendLine(response);

                // check/enforce hard limits (errors, vrfy ...)
                if (_CmdId.Quit != currCmd && connOk)
                {
                    string errMsg = null;
                    if (_msgCount > AppGlobals.MaxMessages)
                    {
                        // above max # of message in a single session
                        errMsg = "451 Session messages count exceeded";
                    }
                    else if (_errCount > AppGlobals.MaxSmtpErr)
                    {
                        // too many errors
                        errMsg = "550 Max errors exceeded";
                    }
                    else if (_vrfyCount > AppGlobals.MaxSmtpVrfy)
                    {
                        // tried to VRFY/EXPN too many addresses
                        errMsg = "451 Max recipient verification exceeded";
                    }
                    else if (_noopCount > AppGlobals.MaxSmtpNoop)
                    {
                        // entered too many NOOP commands
                        errMsg = "451 Max NOOP count exceeded";
                    }
                    else if (_rcptTo.Count > AppGlobals.MaxSmtpRcpt)
                    {
                        // too many recipients for a single message
                        errMsg = "452 Too many recipients";
                    }
                    else if (_earlyTalker)
                    {
                        // early talker
                        errMsg = _etalkerMsg;
                    }
                    if (null != errMsg)
                    {
                        connOk = _SendLine(errMsg);
                        cmdLine = null; // force closing
                    }
                }

                // check if connection Ok
                if (connOk)
                    connOk = _client.Connected;
            } // while null...

            // close/reset this session
            _CloseSession();
        }