You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // SNFMilter.hpp
  2. // Copyright (C) 2007 ARM Research Labs, LLC.
  3. // See www.armresearch.com for the copyright terms.
  4. //
  5. // This file defines the SNFMilter configuration data structures and interface.
  6. #ifndef SNFMilterhpp_included
  7. #define SNFMilterhpp_included
  8. #include <signal.h>
  9. #include <libmilter/mfapi.h>
  10. #include <vector>
  11. #include <string>
  12. #include "MailHeaders.hpp"
  13. #include "timing.hpp"
  14. #include "threading.hpp"
  15. using namespace std;
  16. class snf_EngineHandler; // We must know that these exist.
  17. class snf_RulebaseHandler;
  18. // Connection types.
  19. enum SNFMilterSocketType {
  20. TCPMilterSocket = 1,
  21. UNIXMilterSocket = 2,
  22. NOMilterSocket = 3
  23. };
  24. // SNFMilterAction - What we can do.
  25. enum SNFMilterAction { // SNFMilter Actions
  26. Error = -1, // Error result.
  27. Allow = 0, // Process the message.
  28. Accept = 1, // White-List the message.
  29. Retry = 2, // Return Try Again (tmp fail)
  30. Reject = 3, // Reject the message.
  31. Discard = 4, // Silently discard.
  32. Quarantine = 5, // Store in quarantine.
  33. NoAction = 6, // Take no action.
  34. NMilterActions
  35. };
  36. //
  37. // Configuration.
  38. //
  39. const string AllowActionMnemonic = "0";
  40. const string AcceptActionMnemonic = "1";
  41. const string RetryActionMnemonic = "2";
  42. const string RejectActionMnemonic = "3";
  43. const string DiscardActionMnemonic = "4";
  44. const string QuarantineActionMnemonic = "5";
  45. const string NoActionMnemonic = "6";
  46. const string TCPMilterSocketMnemonic = "1";
  47. const string UNIXMilterSocketMnemonic = "2";
  48. const int ResultCodesCount = 64; // Number of valid result codes.
  49. const int ConfigurationLifetime = 1000; // Config life time in ms.
  50. const bool PrependLocalReceivedHeader = true; // True to prepend local received headers
  51. // to the buffer to scan.
  52. const sfsistat FailSafeMilterResponse = SMFIS_CONTINUE; // Return value to libmilter
  53. // in case of error.
  54. const string::size_type MailBufferReserveSize = 65536; // Maximum amount of email message to scan.
  55. const string SMTPENDL = "\r\n"; // SMTP endline.
  56. const int ShutdownPeriods = 5; // Number of time periods to wait while
  57. // shutting down.
  58. const int ShutdownWaitPeriod_ms = 1000; // Time period duration for shutting down.
  59. const string UnknownExceptionMessage = "Unknown exception occurred."; // Logged when an unknown exception occurs.
  60. const int ShutdownSignal = SIGTERM; // Signal for shutdown.
  61. //
  62. // End of configuration.
  63. //
  64. // The SNFMilterEngine class provides up to date configuration data and
  65. // a scanning engine for the milter. It is presumed that at one of these objects
  66. // will be used in each message scan. They can be created, used, and destroyed,
  67. // or for a more optimized approach they can be created, used, stored in a pool,
  68. // and refreshed, and used again for a new scan. They should all be properly
  69. // destroyed before runLibMilter() returns.
  70. class SNFMilterEngine { // Milter config objec. One per scan.
  71. private:
  72. Mutex ConfigMutex; // Configuration lock mutex.
  73. snf_RulebaseHandler* myRulebase; // Where is my rulebase?
  74. snf_EngineHandler* myEngine; // Where is my engine?
  75. // Configuration data.
  76. // IP scan actions
  77. SNFMilterAction WhiteAction; // Action for White IP.
  78. SNFMilterAction CautionAction; // Action for Caution IP.
  79. SNFMilterAction BlackAction; // Action for Black IP.
  80. SNFMilterAction TruncateAction; // Action for Truncate IP.
  81. SNFMilterAction NonZeroAction; // Action for nonzero scans.
  82. // Message scan actions
  83. SNFMilterAction ResultActions[ResultCodesCount]; // Array of possible scan actions.
  84. Timeout ConfigurationCheckTime; // Timer for checking the configuration.
  85. string RunningConfiguration; // The current running config string.
  86. void readConfiguration(); // Parses the configuration.
  87. void checkConfiguration(); // Reload the config if it is old.
  88. public:
  89. SNFMilterEngine(snf_RulebaseHandler* R); // Construct the configuration.
  90. ~SNFMilterEngine(); // Destroy the configuration.
  91. void setResultAction(int Result, SNFMilterAction Action); // Set a result / action pair.
  92. SNFMilterAction scanIP(unsigned long int IP); // Scans an IP.
  93. SNFMilterAction scanMessage(const unsigned char* bfr, int length); // Scans a message.
  94. string XHeaders(); // Return X headers from last scan.
  95. };
  96. // The SNFMilterContext class maintains the context for a connection
  97. // from the MTA. There is one SNFMilterContext object for each
  98. // connection from the MTA. They can be created, used, and destroyed,
  99. // or for a more optimized approach they can be created, used, stored
  100. // in a pool, and refreshed, and used again for a new scan. They
  101. // should all be properly destroyed before runLibMilter() returns.
  102. class SNFMilterContext { // Milter connection context object.
  103. public:
  104. // Object states. The object transitions to the corresponding state
  105. // when a libmilter callback is invoked. The object is in the
  106. // Pooled state when the object is not being used.
  107. enum SNFMilterState {
  108. Pooled,
  109. Connect,
  110. Helo,
  111. EnvFrom,
  112. EnvRcpt,
  113. Data,
  114. Header,
  115. EOH,
  116. Body,
  117. EOM,
  118. Close,
  119. NMilterStates
  120. } State;
  121. SNFMilterContext(snf_RulebaseHandler *);
  122. ~SNFMilterContext();
  123. sfsistat SkipReturn; // libmilter return value when further
  124. // callbacks of the same type are to be skipped.
  125. // Map the scan result to the libmilter return value.
  126. sfsistat
  127. smfisReturn(SNFMilterAction);
  128. // Scanning engine.
  129. SNFMilterEngine milterEngine;
  130. string getLocalReceivedHeader();
  131. // Connection data.
  132. struct SNFMilterConnectionData {
  133. string HostName;
  134. IP4Address HostIP;
  135. string HostHelo;
  136. // Clear the object.
  137. void clear() {
  138. HostName.clear();
  139. HostIP = (long unsigned )0;
  140. HostHelo.clear();
  141. }
  142. } ConnectionData;
  143. // Message buffer.
  144. struct SNFMilterMessageData {
  145. // Buffer to hold the message.
  146. string MessageBuffer;
  147. // Sender address.
  148. string SenderAddress;
  149. // Constructor reserves memory to hold the message.
  150. SNFMilterMessageData(string::size_type reserveSize) {
  151. MessageBuffer.reserve(reserveSize);
  152. }
  153. // Clear the object.
  154. void clear() {
  155. MessageBuffer.clear();
  156. SenderAddress.clear();
  157. }
  158. } MessageData;
  159. };
  160. class SNFMilterContextPool { // SNFMilter Pool Manager
  161. private:
  162. Mutex ContextAllocationControl; // Protects context allocation.
  163. vector<SNFMilterContext*> ContextPool; // Contains all created contexts.
  164. ProductionQueue<SNFMilterContext*> AvailableContexts; // Contains all available contexts.
  165. snf_RulebaseHandler* myRulebase; // Rulebase handler.
  166. // Connection info.
  167. SNFMilterSocketType MilterSocketType;
  168. string MilterSocketPath;
  169. string MilterSocketGroup;
  170. string MilterSocketIP;
  171. int MilterSocketPort;
  172. public:
  173. SNFMilterContextPool(snf_RulebaseHandler* Rulebase); // Ctor needs a live rulebase handler.
  174. ~SNFMilterContextPool(); // Dtor gracefully discards contexts.
  175. SNFMilterSocketType getSocketType(); // Named pipe or TCP socket specified
  176. // in the configuration.
  177. string getSocketPath(); // Path of named pipe specified in
  178. // the configuration
  179. string getSocketGroup(); // Group specified for named pipe
  180. // in the conofiguration.
  181. string getSocketIP(); // IP (host) specified in the
  182. // configuration.
  183. int getSocketPort(); // TCP port specified in the
  184. // configuration
  185. SNFMilterContext* grab(); // Get an context to use.
  186. void drop(SNFMilterContext* E); // Drop an context after use.
  187. bool allUnused(); // Return true if no contexts are in use.
  188. void logThisError(string ContextName, int Code, string Text); // Log an error message.
  189. void logThisInfo(string ContextName, int Code, string Text); // Log an informational message.
  190. };
  191. // The runLibMilter function establishes the appropriate libmilter call backs and
  192. // accepts calls from the MTA via libmilter until it is told to quit. When it
  193. // is told to quit it gracefully closes down, reclaims any memory it allocated,
  194. // and returns.
  195. // The actual code for the runLibMilter() function call is found in SNFMilter.cpp.
  196. void runLibMilter(SNFMilterContextPool* Contexts, bool DebugMode); // Run the milter 'til it's done.
  197. #endif