Example #1
0
        // MAIL FROM:
        private string cmd_mail(string cmdLine)
        {
            if (string.IsNullOrEmpty(this._heloStr))
            {
                this._errCount++;
                return("503 HELO/EHLO Command not issued");
            }
            if (!string.IsNullOrEmpty(this._mailFrom))
            {
                this._errCount++;
                return("503 Nested MAIL command");
            }
            List <string> parts = parseCmdLine(cmdID.mailFrom, cmdLine);

            if (2 != parts.Count)
            {
                this._errCount++;
                return(String.Format("501 {0} needs argument", parts[0]));
            }
            if (!checkMailAddr(parts[1]))
            {
                this._errCount++;
                return(String.Format("553 Invalid address {0}", parts[1]));
            }
            this._mailFrom = parts[1];
            this._lastCmd  = cmdID.mailFrom;
            return(string.Format("250 {0}... Sender ok", parts[1]));
        }
Example #2
0
 // DATA
 private string cmd_data(string cmdLine)
 {
     if (this._rcptTo.Count < 1)
     {
         this._errCount++;
         return("471 Bad or missing RCPT command");
     }
     this._lastCmd = cmdID.data;
     return("354 Start mail input; end with <CRLF>.<CRLF>");
 }
Example #3
0
 // unknown/unsupported
 private string cmd_unknown(string cmdLine)
 {
     this._errCount++;
     this._lastCmd = cmdID.invalid;
     if (string.IsNullOrEmpty(cmdLine))
     {
         return("500 Command unrecognized");
     }
     else
     {
         return(string.Format("500 Command unrecognized ({0})", cmdLine));
     }
 }
Example #4
0
        // retrieves the command ID from command line args
        private cmdID getCommandID(string cmdLine)
        {
            cmdID  id      = cmdID.invalid;
            string tmpBuff = cmdLine.ToUpperInvariant();

            for (int i = 0; i < this.cmdList.Length; i++)
            {
                if (tmpBuff.StartsWith(this.cmdList[i]))
                {
                    id = (cmdID)i;
                    break;
                }
            }
            return(id);
        }
Example #5
0
        // splits an SMTP command into command and argument(s)
        private List <string> parseCmdLine(cmdID id, string cmdLine)
        {
            List <string> parts = new List <string>();

            if (string.IsNullOrEmpty(cmdLine))
            {
                return(parts);
            }
            try
            {
                string cmdStr = cmdList[(int)id];
                string curCmd = cleanupString(cmdLine);

                int pos = -1;
                if (cmdStr.Contains(':'))
                {
                    pos = cmdLine.IndexOf(':');
                }
                else
                {
                    pos = cmdLine.IndexOf(' ');
                }
                if (-1 != pos)
                {
                    string cmd = cleanupString(cmdLine.Substring(0, pos));
                    string 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);
        }
Example #6
0
        // HELO/EHLO
        private string cmd_helo(string cmdLine)
        {
            cmdID         id    = getCommandID(cmdLine);
            List <string> parts = parseCmdLine(id, cmdLine);

            if (2 != parts.Count)
            {
                this._errCount++;
                return(String.Format("501 {0} needs argument", parts[0]));
            }
            if (!string.IsNullOrEmpty(this._heloStr))
            {
                this._errCount++;
                return(string.Format("503 you already sent {0} ...", parts[0]));
            }

            /*
             * if (!checkHelo(parts[1]))
             * {
             *  this._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 + "]")
             * )
             * {
             *  this._errCount++;
             *  return String.Format("501 spoofed {0}", parts[0]);
             * }
             */
            this._heloStr = parts[1];
            this._lastCmd = id;
            if (id == cmdID.helo)
            {
                return(String.Format("250 Hello {0} ([{1}]), nice to meet you.", parts[1], this._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], this._clientIP));
        }
Example #7
0
        // RCPT TO:
        private string cmd_rcpt(string cmdLine)
        {
            if (string.IsNullOrEmpty(this._mailFrom))
            {
                this._errCount++;
                return("503 Need MAIL before RCPT");
            }
            List <string> parts = parseCmdLine(cmdID.rcptTo, cmdLine);

            if (2 != parts.Count)
            {
                this._errCount++;
                return(String.Format("501 {0} needs argument", parts[0]));
            }
            if (!checkMailAddr(parts[1]))
            {
                this._errCount++;
                return(String.Format("553 Invalid address {0}", parts[1]));
            }

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

            this._rcptTo.Add(parts[1]);
            this._lastCmd = cmdID.rcptTo;
            return(string.Format("250 {0}... Recipient ok", parts[1]));
        }
Example #8
0
        // VRFY/EXPN
        private string cmd_vrfy(string cmdLine)
        {
            cmdID id = getCommandID(cmdLine);

            this._vrfyCount++;
            List <string> parts = parseCmdLine(id, cmdLine);

            if (2 != parts.Count)
            {
                this._errCount++;
                return(String.Format("501 {0} needs argument", parts[0]));
            }
            if (!checkMailAddr(parts[1]))
            {
                this._errCount++;
                return(String.Format("553 Invalid address {0}", parts[1]));
            }
            this._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]));
        }
Example #9
0
 // QUIT
 private string cmd_quit(string cmdLine)
 {
     this._lastCmd = cmdID.quit;
     return("221 Closing connection.");
 }
Example #10
0
 // RSET
 private string cmd_rset(string cmdLine)
 {
     resetSession();
     this._lastCmd = cmdID.rset;
     return("250 Reset Ok");
 }
Example #11
0
 // end of DATA (dot)
 private string cmd_dot(string cmdLine)
 {
     this._lastCmd = cmdID.noop;
     return("250 Queued mail for delivery");
 }
Example #12
0
        public void handleSession()
        {
            string cmdLine  = "?";
            string response = cmd_ok(null);
            cmdID  currCmd  = cmdID.invalid;
            bool   connOk   = true;

            if (false == this._initOk)
            {
                closeSession();
                return;
            }

            // sessions limit reached, reject session
            if (this._sessCount > AppGlobals.maxSessions)
            {
                if (connOk)
                {
                    sendLine(TEMPFAIL_MSG);
                }
                closeSession();
                return;
            }

            // if the remote IP isn't a private one
            if (!isPrivateIP(this._clientIP))
            {
                // checks the incoming IP against whitelists, if listed skip blacklist checks
                bool isDnsListed = isListed(this._clientIP, AppGlobals.whiteLists, "white");
                if (!isDnsListed)
                {
                    // check the IP against blacklists
                    isDnsListed = isListed(this._clientIP, AppGlobals.blackLists, "black");
                    if ((isDnsListed) && (!AppGlobals.storeData))
                    {
                        // if blacklisted and NOT storing messages
                        sendLine(string.Format(DNSBL_MSG, this._clientIP, this._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);
            this._earlyTalker = isEarlyTalker();
            if (this._earlyTalker)
            {
                sendLine(ETALKER_MSG);
                closeSession();
                return;
            }

            // all ok, send out our banner
            connOk = sendLine(cmd_banner(null));
            while ((null != cmdLine) && (true == connOk))
            {
                if (this._lastCmd == cmdID.data)
                {
                    string mailMsg = recvData();
                    if (this._timedOut)
                    {
                        // got a receive timeout during the DATA phase
                        if (connOk)
                        {
                            sendLine(TIMEOUT_MSG);
                        }
                        closeSession();
                        return;
                    }
                    response = cmd_dot(null);
                    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
                            if (connOk)
                            {
                                sendLine(TEMPFAIL_MSG);
                            }
                            closeSession();
                            return;
                        }
                    }
                    resetSession();
                }
                else
                {
                    // read an SMTP command line and deal with the command
                    cmdLine = recvLine();
                    if (null != cmdLine)
                    {
                        logCmdAndResp(DIR_RX, cmdLine);
                        currCmd = getCommandID(cmdLine);
                        Console.WriteLine(currCmd);
                        switch (currCmd)
                        {
                        case cmdID.helo:                // HELO
                            response = cmd_helo(cmdLine);
                            break;

                        case cmdID.ehlo:                // EHLO
                            response = cmd_helo(cmdLine);
                            break;

                        case cmdID.mailFrom:            // MAIL FROM:
                            response = cmd_mail(cmdLine);
                            break;

                        case cmdID.rcptTo:              // RCPT TO:
                            response = cmd_rcpt(cmdLine);
                            break;

                        case cmdID.data:                // DATA
                            if ((AppGlobals.doTempFail) && (!AppGlobals.storeData))
                            {
                                // emit a tempfail upon receiving the DATA command
                                response      = TEMPFAIL_MSG;
                                cmdLine       = null;
                                this._lastCmd = currCmd = cmdID.quit;
                            }
                            else
                            {
                                response = cmd_data(cmdLine);
                            }
                            break;

                        case cmdID.rset:                // RSET
                            response = cmd_rset(cmdLine);
                            break;

                        case cmdID.quit:        // QUIT
                            response = cmd_quit(cmdLine);
                            cmdLine  = null;    // force closing
                            break;

                        case cmdID.vrfy:                // VRFY
                            response = cmd_vrfy(cmdLine);
                            break;

                        case cmdID.expn:                // EXPN
                            response = cmd_vrfy(cmdLine);
                            break;

                        case cmdID.help:                // HELP
                            response = cmd_help(cmdLine);
                            break;

                        case cmdID.noop:                // NOOP
                            response = cmd_noop(cmdLine);
                            break;

                        default:                        // unkown/unsupported
                            response = cmd_unknown(cmdLine);
                            break;
                        }
                    }
                    else
                    {
                        // the read timed out (or we got an error), emit a message and drop the connection
                        response = TIMEOUT_MSG;
                        currCmd  = cmdID.quit;
                    }
                }

                // send response
                if ((this._errCount > 0) && (cmdID.quit != currCmd))
                {
                    // tarpit a bad client, time increases with error count
                    sleepDown(AppGlobals.errorDelay * this._errCount);
                }
                else
                {
                    // add a short delay
                    sleepDown(25);
                }

                // checks for early talkers
                this._earlyTalker = isEarlyTalker();

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

                // check/enforce hard limits (errors, vrfy ...)
                if ((cmdID.quit != currCmd) && (connOk))
                {
                    string errMsg = null;
                    if (this._msgCount > AppGlobals.maxMessages)
                    {
                        // above max # of message in a single session
                        errMsg = "451 Session messages count exceeded";
                    }
                    else if (this._errCount > AppGlobals.maxSmtpErr)
                    {
                        // too many errors
                        errMsg = "550 Max errors exceeded";
                    }
                    else if (this._vrfyCount > AppGlobals.maxSmtpVrfy)
                    {
                        // tried to VRFY/EXPN too many addresses
                        errMsg = "451 Max recipient verification exceeded";
                    }
                    else if (this._noopCount > AppGlobals.maxSmtpNoop)
                    {
                        // entered too many NOOP commands
                        errMsg = "451 Max NOOP count exceeded";
                    }
                    else if (this._rcptTo.Count > AppGlobals.maxSmtpRcpt)
                    {
                        // too many recipients for a single message
                        errMsg = "452 Too many recipients";
                    }
                    else if (this._earlyTalker)
                    {
                        // early talker
                        errMsg = ETALKER_MSG;
                    }
                    if (null != errMsg)
                    {
                        if (connOk)
                        {
                            connOk = sendLine(errMsg);
                        }
                        cmdLine = null; // force closing
                    }
                }

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

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