/// <summary> /// Filters sender. /// </summary> /// <param name="from">Sender.</param> /// <param name="api">Reference to server API.</param> /// <param name="session">Reference to SMTP session.</param> /// <param name="errorText">Filtering error text what is returned to client. ASCII text, 100 chars maximum.</param> /// <returns>Returns true if sender is ok or false if rejected.</returns> public bool Filter(string from, IMailServerApi api, SMTP_Session session, out string errorText) { errorText = null; bool ok = false; // Don't check authenticated users or LAN IP if (session.IsAuthenticated || IsPrivateIP(session.RemoteEndPoint.Address)) { return(true); } try { using (new TransactionScope(TransactionScopeOption.Suppress)) { var d = new NKDC(ApplicationConnectionString, null); if (!(from o in d.ContactEmailsViews where o.Email == @from select o).Any()) { errorText = "You must be a registered user to use the email support service."; WriteFilterLog("Sender:" + from + " IP:" + session.RemoteEndPoint.Address.ToString() + " unregistered.\r\n"); return(false); } else { return(true); } } } catch (Exception ex) { WriteFilterLog(string.Format("Sender:{0} IP:{1} caused exception.\r\nEX:{2}{3}\r\n__\r\n", from, session.RemoteEndPoint.Address, ex, ex.Message)); } return(ok); }
/// <summary> /// Filters sender. /// </summary> /// <param name="from">Sender.</param> /// <param name="api">Reference to server API.</param> /// <param name="session">Reference to SMTP session.</param> /// <param name="errorText">Filtering error text what is returned to client. ASCII text, 100 chars maximum.</param> /// <returns>Returns true if sender is ok or false if rejected.</returns> public bool Filter(string from,IMailServerApi api,SMTP_Session session,out string errorText) { errorText = ""; string ip = session.RemoteEndPoint.Address.ToString(); Dns_Client dns = new Dns_Client(); bool ok = false; // Don't check PTR for authenticated session and LAN IP ranges if(session.Authenticated || ip.StartsWith("127.0.0.1") || ip.StartsWith("10.") || ip.StartsWith("192.168")){ return true; } DnsServerResponse reponse = dns.Query(ip,QTYPE.PTR); if(reponse.ResponseCode == RCODE.NO_ERROR){ foreach(PTR_Record rec in reponse.GetPTRRecords()){ if(rec.DomainName.ToLower() == session.EhloName.ToLower()){ ok = true; break; } } } if(!ok){ errorText = "Bad EHLO/HELO name, you must have valid DNS PTR record for your EHLO name and IP."; } return ok; }
/// <summary> /// Default constructor. /// </summary> /// <param name="server">Server what owns this virtual server.</param> /// <param name="id">Virtual server ID.</param> /// <param name="name">Virtual server name.</param> /// <param name="apiInitString">Virtual server api initi string.</param> /// <param name="api">Virtual server API.</param> public VirtualServer(Server server,string id,string name,string apiInitString,IMailServerApi api) { m_pOwnerServer = server; m_ID = id; m_Name = name; m_ApiInitString = apiInitString; m_pApi = api; }
/// <summary> /// Default constructor. /// </summary> /// <param name="server"></param> /// <param name="api"></param> public FetchPop3(VirtualServer server,IMailServerApi api) { m_pServer = server; m_pApi = api; m_LastFetch = DateTime.Now.AddMinutes(-5); m_pTimer = new Timer(); m_pTimer.Interval = 15000; m_pTimer.Elapsed += new ElapsedEventHandler(m_pTimer_Elapsed); }
/// <summary> /// Default constructor. /// </summary> /// <param name="api">Virtual server api</param> public RecycleBinManager(IMailServerApi api) { m_pApi = api; m_pTimer = new Timer(); m_pTimer.Interval = 1000 * 60 * 60; m_pTimer.Elapsed += new ElapsedEventHandler(m_pTimer_Elapsed); m_LastCleanTime = DateTime.MinValue; }
/// <summary> /// Default constructor. /// </summary> /// <param name="server"></param> /// <param name="api"></param> public FetchPop3(VirtualServer server, IMailServerApi api) { m_pServer = server; m_pApi = api; m_LastFetch = DateTime.Now.AddMinutes(-5); m_pTimer = new Timer(); m_pTimer.Interval = 15000; m_pTimer.Elapsed += new ElapsedEventHandler(m_pTimer_Elapsed); }
/// <summary> /// Default constructor. /// </summary> /// <param name="api">Virtual server api</param> public RecycleBinManager(IMailServerApi api) { m_pApi = api; m_pTimer = new Timer(); m_pTimer.Interval = 1000 * 60 * 60; m_pTimer.Elapsed += new ElapsedEventHandler(m_pTimer_Elapsed); m_pTimer.Enabled = true; m_LastCleanTime = DateTime.MinValue; }
/// <summary> /// Filters message. /// </summary> /// <param name="messageStream">Message stream which to filter.</param> /// <param name="filteredStream">Filtered stream.</param> /// <param name="sender">Senders email address.</param> /// <param name="recipients">Recipients email addresses.</param> /// <param name="api">Access to server API.</param> /// <param name="session">Reference to SMTP session.</param> /// <param name="errorText">Filtering error text what is returned to client. ASCII text, 500 chars maximum.</param> public FilterResult Filter(Stream messageStream,out Stream filteredStream,string sender,string[] recipients,IMailServerApi api,SMTP_Session session,out string errorText) { errorText = ""; filteredStream = messageStream; try{ messageStream.Position = 0; // long pos = messageStream.Position; string headers = MimeUtils.ParseHeaders(messageStream).ToLower(); // messageStream.Position = pos; //--- Check required header fields ---------// bool headersOk = true; if(headers.IndexOf("from:") == -1){ errorText = "Required From: header field is missing !"; headersOk = false; } else if(headers.IndexOf("to:") == -1){ errorText = "Required To: header field is missing !"; headersOk = false; } else if(headers.IndexOf("subject:") == -1){ errorText = "Required Subject: header field is missing !"; headersOk = false; } //------------------------------------------// // Check invalid <CR> or <LF> in headers. Header may not contain <CR> without <LF>, // <CRLF> must be in pairs. if(headers.Replace("\r\n","").IndexOf("\r") > -1 || headers.Replace("\r\n","").IndexOf("\n") > -1){ errorText = "Message contains invalid <CR> or <LF> combinations !"; headersOk = false; } //-------------------------------------------------------------------------------// if(!headersOk){ return FilterResult.Error; } } catch{ } // Reset stream position messageStream.Position = 0; return FilterResult.Store; }
/// <summary> /// Filters sender. /// </summary> /// <param name="from">Sender.</param> /// <param name="api">Reference to server API.</param> /// <param name="session">Reference to SMTP session.</param> /// <param name="errorText">Filtering error text what is returned to client. ASCII text, 100 chars maximum.</param> /// <returns>Returns true if sender is ok or false if rejected.</returns> public bool Filter(string from, IMailServerApi api, SMTP_Session session, out string errorText) { errorText = null; bool ok = false; // Don't check authenticated users or LAN IP if (session.IsAuthenticated || IsPrivateIP(session.RemoteEndPoint.Address)) { return true; } try { using (new TransactionScope(TransactionScopeOption.Suppress)) { var d = new NKDC(ApplicationConnectionString, null); if (!(from o in d.ContactEmailsViews where o.Email == @from select o).Any()) { errorText = "You must be a registered user to use the email support service."; WriteFilterLog("Sender:" + from + " IP:" + session.RemoteEndPoint.Address.ToString() + " unregistered.\r\n"); return false; } else { return true; } } } catch (Exception ex) { WriteFilterLog(string.Format("Sender:{0} IP:{1} caused exception.\r\nEX:{2}{3}\r\n__\r\n", from, session.RemoteEndPoint.Address, ex, ex.Message)); } return ok; }
/// <summary> /// Loads virtual server from xml file. /// </summary> internal void LoadVirtualServers() { try{ if (!File.Exists(SCore.PathFix(m_StartupPath + "Settings\\localServers.xml"))) { return; } DateTime dateServers = File.GetLastWriteTime(SCore.PathFix(m_StartupPath + "Settings\\localServers.xml")); if (DateTime.Compare(dateServers, m_ServersFileDate) != 0) { m_ServersFileDate = dateServers; DataSet ds = new DataSet(); ds.Tables.Add("Servers"); ds.Tables["Servers"].Columns.Add("ID"); ds.Tables["Servers"].Columns.Add("Enabled"); ds.Tables["Servers"].Columns.Add("Name"); ds.Tables["Servers"].Columns.Add("API_assembly"); ds.Tables["Servers"].Columns.Add("API_class"); ds.Tables["Servers"].Columns.Add("API_initstring"); ds.ReadXml(SCore.PathFix(m_StartupPath + "Settings\\localServers.xml")); if (ds.Tables.Contains("Servers")) { // Delete running virtual servers what has deleted. for (int i = 0; i < m_pVirtualServers.Count; i++) { VirtualServer server = m_pVirtualServers[i]; bool exists = false; foreach (DataRow dr in ds.Tables["Servers"].Rows) { if (server.ID == dr["ID"].ToString()) { exists = true; break; } } if (!exists) { server.Stop(); m_pVirtualServers.Remove(server); i--; } } // Add new added virtual servers what aren't running already. foreach (DataRow dr in ds.Tables["Servers"].Rows) { //--- See if specified server already running, if so, skip it. --// bool exists = false; foreach (VirtualServer server in m_pVirtualServers) { if (server.ID == dr["ID"].ToString()) { exists = true; server.Enabled = ConvertEx.ToBoolean(dr["Enabled"], true); break; } } if (exists) { continue; } //--------------------------------------------------------------// string id = dr["ID"].ToString(); string name = dr["Name"].ToString(); string assembly = dr["API_assembly"].ToString(); string apiClass = dr["API_class"].ToString(); string intiStr = dr["API_initstring"].ToString(); IMailServerApi api = LoadApi(assembly, apiClass, intiStr); VirtualServer virtualServer = new VirtualServer(this, id, name, intiStr, api); m_pVirtualServers.Add(virtualServer); virtualServer.Enabled = ConvertEx.ToBoolean(dr["Enabled"], true); } } } } catch (Exception x) { Error.DumpError(x, new System.Diagnostics.StackTrace()); } }
/// <summary> /// Restores specified message from recycle bin. /// </summary> /// <param name="messageID">Message ID which to restore.</param> /// <param name="api">Reference to API.</param> public static void RestoreFromRecycleBin(string messageID, IMailServerApi api) { using (FileStream fs = GetFile()){ int delRowCount = 0; StreamLineReader r = new StreamLineReader(fs); long pos = fs.Position; string line = r.ReadLineString(); while (line != null) { // Skip comment lines if (!line.StartsWith("#")) { // Skip deleted row if (line.StartsWith("\0")) { delRowCount++; } else { string[] row = TextUtils.SplitQuotedString(line, ' '); // Delete row if (row[0] == messageID) { string user = row[2]; string folder = TextUtils.UnQuoteString(row[3]); // Store message back to original user folder using (FileStream stream = File.OpenRead(m_RecycleBinPath + messageID + ".eml")){ // If folder doesn't exist, create it if (!api.FolderExists(user + "/" + folder)) { api.CreateFolder("system", user, folder); } api.StoreMessage("system", user, folder, stream, DateTime.Now, new string[] { "Recent" }); } // Delete row byte[] linebytes = new byte[fs.Position - pos - 2]; fs.Position = pos; fs.Write(linebytes, 0, linebytes.Length); fs.Position += 2; // CRLF delRowCount++; // Delete recycle bin message File.Delete(m_RecycleBinPath + messageID + ".eml"); break; } } } pos = fs.Position; line = r.ReadLineString(); } // There are many deleted rows, vacuum(remove deleted rows) flags database. if (delRowCount > 500) { Vacuum(fs); } } }
/// <summary> /// Restores specified message from recycle bin. /// </summary> /// <param name="messageID">Message ID which to restore.</param> /// <param name="api">Reference to API.</param> public static void RestoreFromRecycleBin(string messageID,IMailServerApi api) { using(FileStream fs = GetFile()){ int delRowCount = 0; StreamLineReader r = new StreamLineReader(fs); long pos = fs.Position; string line = r.ReadLineString(); while(line != null){ // Skip comment lines if(!line.StartsWith("#")){ // Skip deleted row if(line.StartsWith("\0")){ delRowCount++; } else{ string[] row = TextUtils.SplitQuotedString(line,' '); // Delete row if(row[0] == messageID){ string user = row[2]; string folder = TextUtils.UnQuoteString(row[3]); // Store message back to original user folder using(FileStream stream = File.OpenRead(m_RecycleBinPath + messageID + ".eml")){ // If folder doesn't exist, create it if(!api.FolderExists(user + "/" + folder)){ api.CreateFolder("system",user,folder); } api.StoreMessage("system",user,folder,stream,DateTime.Now,new string[]{"Recent"}); } // Delete row byte[] linebytes = new byte[fs.Position - pos - 2]; fs.Position = pos; fs.Write(linebytes,0,linebytes.Length); fs.Position += 2; // CRLF delRowCount++; // Delete recycle bin message File.Delete(m_RecycleBinPath + messageID + ".eml"); break; } } } pos = fs.Position; line = r.ReadLineString(); } // There are many deleted rows, vacuum(remove deleted rows) flags database. if(delRowCount > 500){ Vacuum(fs); } } }
/// <summary> /// Filters sender. /// </summary> /// <param name="from">Sender.</param> /// <param name="api">Reference to server API.</param> /// <param name="session">Reference to SMTP session.</param> /// <param name="errorText">Filtering error text what is returned to client. ASCII text, 100 chars maximum.</param> /// <returns>Returns true if sender is ok or false if rejected.</returns> public bool Filter(string from,IMailServerApi api,SMTP_Session session,out string errorText) { errorText = null; bool ok = true; // Don't check authenticated users or LAN IP if(session.IsAuthenticated || IsPrivateIP(session.RemoteEndPoint.Address)){ return true; } try{ //--- Load data ----------------------- DataSet ds = new DataSet(); ds.Tables.Add("General"); ds.Tables["General"].Columns.Add("CheckHelo"); ds.Tables["General"].Columns.Add("LogRejections"); ds.Tables.Add("BlackListSettings"); ds.Tables["BlackListSettings"].Columns.Add("ErrorText"); ds.Tables.Add("BlackList"); ds.Tables["BlackList"].Columns.Add("IP"); ds.Tables.Add("Servers"); ds.Tables["Servers"].Columns.Add("Cost"); ds.Tables["Servers"].Columns.Add("Server"); ds.Tables["Servers"].Columns.Add("DefaultRejectionText"); ds.ReadXml(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\lsDNSBL_Filter_db.xml"); bool logRejections = false; #region General if(ds.Tables["General"].Rows.Count == 1){ if(Convert.ToBoolean(ds.Tables["General"].Rows[0]["CheckHelo"])){ DnsServerResponse response = Dns_Client.Static.Query(session.EhloHost,DNS_QType.A); // If dns server connection errors, don't block. if(response.ConnectionOk && response.ResponseCode != DNS_RCode.SERVER_FAILURE){ bool found = false; foreach(DNS_rr_A a in response.GetARecords()){ if(session.RemoteEndPoint.Address.Equals(a.IP)){ found = true; break; } } if(!found){ errorText = "Not valid DNS EHLO/HELO name for your IP '" + session.EhloHost + "' !"; return false; } } } logRejections = ConvertEx.ToBoolean(ds.Tables["General"].Rows[0]["LogRejections"]); } #endregion #region Balck List foreach(DataRow dr in ds.Tables["BlackList"].Rows){ if(IsAstericMatch(dr["IP"].ToString(),session.RemoteEndPoint.Address.ToString())){ errorText = ds.Tables["BlackListSettings"].Rows[0]["ErrorText"].ToString(); return false; } } #endregion #region DNSBL foreach(DataRow dr in ds.Tables["Servers"].Rows){ DnsServerResponse dnsResponse = Dns_Client.Static.Query(ReverseIP(session.RemoteEndPoint.Address) + "." + dr["Server"].ToString(),DNS_QType.ANY); DNS_rr_A[] recs = dnsResponse.GetARecords(); if(recs.Length > 0){ if(logRejections){ WriteFilterLog("Sender:" + from + " IP:" + session.RemoteEndPoint.Address.ToString() + " blocked\r\n"); } errorText = dr["DefaultRejectionText"].ToString(); // Server provided return text, use it if(dnsResponse.GetTXTRecords().Length > 0){ errorText = dnsResponse.GetTXTRecords()[0].Text; } if(errorText == ""){ errorText = "You are in '" + dr["Server"].ToString() + "' rejection list !"; } return false; } } #endregion } catch{ } return ok; }
/// <summary> /// Filters message. /// </summary> /// <param name="messageStream">Message stream which to filter.</param> /// <param name="filteredStream">Filtered stream.</param> /// <param name="sender">Senders email address.</param> /// <param name="recipients">Recipients email addresses.</param> /// <param name="api">Access to server API.</param> /// <param name="session">Reference to SMTP session.</param> /// <param name="errorText">Filtering error text what is returned to client. ASCII text, 500 chars maximum.</param> public FilterResult Filter(Stream messageStream,out Stream filteredStream,string sender,string[] recipients,IMailServerApi api,SMTP_Session session,out string errorText) { errorText = ""; messageStream.Position = 0; filteredStream = messageStream; // we don't change message content, just return same stream try{ //--- Load data ----------------------- DataSet ds = new DataSet(); DataTable dt = ds.Tables.Add("KewWords"); dt.Columns.Add("Cost",typeof(int)); dt.Columns.Add("KeyWord"); dt = ds.Tables.Add("ContentMd5"); dt.Columns.Add("Description"); dt.Columns.Add("EntryMd5Value"); ds.ReadXml(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\lsSpam_db.xml"); //--- Do mime parts data md5 hash compare ---------------- ArrayList entries = new ArrayList(); Mime parser = Mime.Parse(messageStream); System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create(); foreach(MimeEntity ent in parser.MimeEntities){ if(ent.Data != null){ string md5Hash = Convert.ToBase64String(md5.ComputeHash(ent.Data)); foreach(DataRow dr in ds.Tables["ContentMd5"].Rows){ // Message contains blocked content(attachment,...) if(dr["EntryMd5Value"].ToString() == md5Hash){ WriteFilterLog(DateTime.Now.ToString() + " From:" + sender + " Subject:\"" + parser.MainEntity.Subject + "\" Contained blocked content:hash=" + md5Hash + "\r\n"); return FilterResult.DontStore; } } } } byte[] topLines = new byte[2000]; if(messageStream.Length < 2000){ topLines = new byte[messageStream.Length]; } messageStream.Read(topLines,0,topLines.Length); string lines = System.Text.Encoding.ASCII.GetString(topLines).ToLower(); //--- Try spam keywords ----------- int totalCost = 0; string keyWords = ""; DataView dv = ds.Tables["KewWords"].DefaultView; dv.Sort = "Cost DESC"; foreach(DataRowView drV in dv){ if(lines.IndexOf(drV.Row["KeyWord"].ToString().ToLower()) > -1){ totalCost += Convert.ToInt32(drV.Row["Cost"]); keyWords += drV.Row["KeyWord"].ToString() + " cost:" + drV.Row["Cost"].ToString() + " "; // Check that total cost isn't exceeded if(totalCost > 99){ errorText = "Message was blocked by server and considered as SPAM !"; WriteFilterLog(DateTime.Now.ToString() + " From:" + sender + " Blocked KeyWords: " + keyWords + "\r\n"); return FilterResult.Error; } } } //--------------------------------- // Reset stream position messageStream.Position = 0; return FilterResult.Store; } catch(Exception x){ return FilterResult.DontStore; } }
/// <summary> /// Filters message. /// </summary> /// <param name="messageStream">Message stream which to filter.</param> /// <param name="filteredStream">Filtered stream.</param> /// <param name="sender">Senders email address.</param> /// <param name="recipients">Recipients email addresses.</param> /// <param name="api">Access to server API.</param> /// <param name="session">Reference to SMTP session.</param> /// <param name="errorText">Filtering error text what is returned to client. ASCII text, 500 chars maximum.</param> public FilterResult Filter(Stream messageStream, out Stream filteredStream, string sender, string[] recipients, IMailServerApi api, SMTP_Session session, out string errorText) { errorText = null; filteredStream = null; try{ // Store message to tmp file string file = API_Utlis.PathFix(Path.GetTempPath() + "\\" + Guid.NewGuid().ToString() + ".eml"); using (FileStream fs = File.Create(file)){ byte[] data = new byte[messageStream.Length]; messageStream.Read(data, 0, data.Length); fs.Write(data, 0, data.Length); } // Execute virus program to scan tmp message // #FileName - place holder is replaced with file DataSet ds = new DataSet(); ds.Tables.Add("Settings"); ds.Tables["Settings"].Columns.Add("Program"); ds.Tables["Settings"].Columns.Add("Arguments"); ds.Tables["Settings"].Columns.Add("VirusExitCode"); ds.ReadXml(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\lsVirusFilter_db.xml"); string virusSoft = ds.Tables["Settings"].Rows[0]["Program"].ToString(); string virusSoftArgs = ds.Tables["Settings"].Rows[0]["Arguments"].ToString().Replace("#FileName", file); int virusExitCode = ConvertEx.ToInt32(ds.Tables["Settings"].Rows[0]["Program"], 1); int exitCode = 0; System.Diagnostics.ProcessStartInfo sInf = new System.Diagnostics.ProcessStartInfo(virusSoft, virusSoftArgs); sInf.CreateNoWindow = true; sInf.UseShellExecute = false; System.Diagnostics.Process p = System.Diagnostics.Process.Start(sInf); if (p != null) { p.WaitForExit(60000); exitCode = p.ExitCode; } if (File.Exists(file)) { // Return scanned message and delete tmp file using (FileStream fs = File.OpenRead(file)){ byte[] data = new byte[fs.Length]; fs.Read(data, 0, data.Length); filteredStream = new MemoryStream(data); } File.Delete(file); } // Virus scanner deleted messaeg, probably contains virus else { virusExitCode = exitCode; } // Do exit code mapping if (virusExitCode == exitCode) { errorText = "Message is blocked, contains virus !"; return(FilterResult.Error); } } catch (Exception x) { string dummy = x.Message; // Virus scanning failed, allow message through filteredStream = messageStream; } return(FilterResult.Store); }
/// <summary> /// Filters message. /// </summary> /// <param name="messageStream">Message stream which to filter.</param> /// <param name="filteredStream">Filtered stream.</param> /// <param name="sender">Senders email address.</param> /// <param name="recipients">Recipients email addresses.</param> /// <param name="api">Access to server API.</param> /// <param name="session">Reference to SMTP session.</param> /// <param name="errorText">Filtering error text what is returned to client. ASCII text, 500 chars maximum.</param> public FilterResult Filter(Stream messageStream,out Stream filteredStream,string sender,string[] recipients,IMailServerApi api,SMTP_Session session,out string errorText) { errorText = null; filteredStream = null; try{ // Store message to tmp file string file = API_Utlis.PathFix(Path.GetTempPath() + "\\" + Guid.NewGuid().ToString() + ".eml"); using(FileStream fs = File.Create(file)){ byte[] data = new byte[messageStream.Length]; messageStream.Read(data,0,data.Length); fs.Write(data,0,data.Length); } // Execute virus program to scan tmp message // #FileName - place holder is replaced with file DataSet ds = new DataSet(); ds.Tables.Add("Settings"); ds.Tables["Settings"].Columns.Add("Program"); ds.Tables["Settings"].Columns.Add("Arguments"); ds.Tables["Settings"].Columns.Add("VirusExitCode"); ds.ReadXml(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\lsVirusFilter_db.xml"); string virusSoft = ds.Tables["Settings"].Rows[0]["Program"].ToString(); string virusSoftArgs = ds.Tables["Settings"].Rows[0]["Arguments"].ToString().Replace("#FileName",file); int virusExitCode = ConvertEx.ToInt32(ds.Tables["Settings"].Rows[0]["Program"],1); int exitCode = 0; System.Diagnostics.ProcessStartInfo sInf = new System.Diagnostics.ProcessStartInfo(virusSoft,virusSoftArgs); sInf.CreateNoWindow = true; sInf.UseShellExecute = false; System.Diagnostics.Process p = System.Diagnostics.Process.Start(sInf); if(p != null){ p.WaitForExit(60000); exitCode = p.ExitCode; } if(File.Exists(file)){ // Return scanned message and delete tmp file using(FileStream fs = File.OpenRead(file)){ byte[] data = new byte[fs.Length]; fs.Read(data,0,data.Length); filteredStream = new MemoryStream(data); } File.Delete(file); } // Virus scanner deleted messaeg, probably contains virus else{ virusExitCode = exitCode; } // Do exit code mapping if(virusExitCode == exitCode){ errorText = "Message is blocked, contains virus !"; return FilterResult.Error; } } catch(Exception x){ string dummy = x.Message; // Virus scanning failed, allow message through filteredStream = messageStream; } return FilterResult.Store; }
/// <summary> /// Filters sender. /// </summary> /// <param name="from">Sender.</param> /// <param name="api">Reference to server API.</param> /// <param name="session">Reference to SMTP session.</param> /// <param name="errorText">Filtering error text what is returned to client. ASCII text, 100 chars maximum.</param> /// <returns>Returns true if sender is ok or false if rejected.</returns> public bool Filter(string from, IMailServerApi api, SMTP_Session session, out string errorText) { errorText = null; bool ok = true; // Don't check authenticated users or LAN IP if (session.IsAuthenticated || IsPrivateIP(session.RemoteEndPoint.Address)) { return(true); } try{ //--- Load data ----------------------- DataSet ds = new DataSet(); ds.Tables.Add("General"); ds.Tables["General"].Columns.Add("CheckHelo"); ds.Tables["General"].Columns.Add("LogRejections"); ds.Tables.Add("BlackListSettings"); ds.Tables["BlackListSettings"].Columns.Add("ErrorText"); ds.Tables.Add("BlackList"); ds.Tables["BlackList"].Columns.Add("IP"); ds.Tables.Add("Servers"); ds.Tables["Servers"].Columns.Add("Cost"); ds.Tables["Servers"].Columns.Add("Server"); ds.Tables["Servers"].Columns.Add("DefaultRejectionText"); ds.ReadXml(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\lsDNSBL_Filter_db.xml"); bool logRejections = false; #region General if (ds.Tables["General"].Rows.Count == 1) { if (Convert.ToBoolean(ds.Tables["General"].Rows[0]["CheckHelo"])) { DnsServerResponse response = Dns_Client.Static.Query(session.EhloHost, DNS_QType.A); // If dns server connection errors, don't block. if (response.ConnectionOk && response.ResponseCode != DNS_RCode.SERVER_FAILURE) { bool found = false; foreach (DNS_rr_A a in response.GetARecords()) { if (session.RemoteEndPoint.Address.Equals(a.IP)) { found = true; break; } } if (!found) { errorText = "Not valid DNS EHLO/HELO name for your IP '" + session.EhloHost + "' !"; return(false); } } } logRejections = ConvertEx.ToBoolean(ds.Tables["General"].Rows[0]["LogRejections"]); } #endregion #region Balck List foreach (DataRow dr in ds.Tables["BlackList"].Rows) { if (IsAstericMatch(dr["IP"].ToString(), session.RemoteEndPoint.Address.ToString())) { errorText = ds.Tables["BlackListSettings"].Rows[0]["ErrorText"].ToString(); return(false); } } #endregion #region DNSBL foreach (DataRow dr in ds.Tables["Servers"].Rows) { DnsServerResponse dnsResponse = Dns_Client.Static.Query(ReverseIP(session.RemoteEndPoint.Address) + "." + dr["Server"].ToString(), DNS_QType.ANY); DNS_rr_A[] recs = dnsResponse.GetARecords(); if (recs.Length > 0) { if (logRejections) { WriteFilterLog("Sender:" + from + " IP:" + session.RemoteEndPoint.Address.ToString() + " blocked\r\n"); } errorText = dr["DefaultRejectionText"].ToString(); // Server provided return text, use it if (dnsResponse.GetTXTRecords().Length > 0) { errorText = dnsResponse.GetTXTRecords()[0].Text; } if (errorText == "") { errorText = "You are in '" + dr["Server"].ToString() + "' rejection list !"; } return(false); } } #endregion } catch { } return(ok); }