@@ -0,0 +1,4 @@ | |||
Included with this distribution are the open-source "wget" and "gzip" files. They are | |||
used in getRulebase.bat to download and decompress rulebase files. The "wget" and "gzip" | |||
utilities included here came from http://unxutils.sourceforge.net/ and are included only | |||
for your convenience. |
@@ -0,0 +1,449 @@ | |||
SNF MDaemon Plugin Change Log... | |||
------------------------------------------------------------------------------ | |||
20080626 - Version 3.0, It's official. | |||
Changed build information. | |||
Removed extraneous comments from configuration file. | |||
20080524 - Version V2-9rc6.25.7 | |||
Optimized networking library for additional speed & stability by moving | |||
receive buffer allocation from heap to stack (automatic). | |||
Optimized timing parameters in SNFClient for improved speed. Polling dealys | |||
are now reduced to 10ms from 30ms. | |||
Removed speed-bug in SNFClient, 100ms guard time between retries was always | |||
executed after an attempt (even a successful attempt). The guard time is now | |||
condition and only fires on unsuccessful attempts. | |||
Updated XCI server logic to ensure non-blocking sockets for clients in all | |||
socket implementations. | |||
20080424 - Version V2-9rc6.24.6 | |||
Refactored snfScanData.clear() to reduce heap work and fragments. | |||
Added mutex to scanMessageFile() entry point just in case some app attempts to | |||
put multiple threads through a single engine handler. scanMessage() is already | |||
protected and fully wraped by the new scanMessageFile() mutex. | |||
Added non-specific runtime exception handling to XHDR injection code. | |||
Added 2 retries w/ 300ms delay to remove original message in XHDR inject code. | |||
If remove fails after 3 attempts the injector throws. | |||
Added 2 retries w/ 300ms delay to rename temp file to msg in XHDR inject code. | |||
If rename fails after 3 attempts the injector throws. | |||
Added IPTest logging. | |||
20080416 - Version V2-9rc5.23.6 | |||
Fixed bug where SNCY open() would fail on some Win* platforms with | |||
WSAEINVAL instead of the standard EINPROGRESS or EALREADY which were expected. | |||
Also added WSAEWOULDBLOCK to cover other "ambiguities" in windows sockets | |||
implementations. InProgress() on Win* now test for any of: | |||
WSAEINPROGRESS, WSAEALREADY, WSAEWOULDBLOCK, WSAEINVAL | |||
20080413 - Version V2-9rc5.22.6 | |||
Fixed bug in TCPHost.open() where EALREADY was not counted as a version of | |||
EINPROGRESS. This would cause open() to throw an unnecessary exception when | |||
an open() required extra time. | |||
20080413 - Version V2-9rc5.21.6 | |||
Extended timeout for SYNC session open() to the full session length. This way | |||
if a session takes a long time to open it still has a shot at success. | |||
20080411 - Version V2-9rc5.20.6 | |||
Adjusted snfNETmgr to use non-blocking open in SYNC sessions. Open timeout | |||
is 1/3 of the session timeout. Session timeout is 2 * Session pacing. Open | |||
polling uses golden spiral delay from 10ms to 340ms. | |||
20080410 - Version V2-9rc5.19.6 | |||
Adjusted XCI manager to use new snfCFGPacket paradigm in checkCFG(). | |||
Adjusted snf_RulebaseHandler::addRulePanic() to use MyMutex and eliminated | |||
the AutoPanicMutex and waiting scheme. | |||
Refactored scanMessage() to use a ScopeMutex() rather than lock()/unlock(). | |||
Refactored scanMessage() to use MyCFGPacket.isRulePanic() test. | |||
Redesigned snfCFGPacket handling to automate grab() / drop() functions. | |||
Fixed lock-up bug: Redesigned AutoPanic posting and checking mechanisms to | |||
eliminate potential dead-lock condition. Under some conditions a precisely | |||
timed auto-panic posting could cause the RulebaesHandler mutex and the | |||
AutoPanicMutex to become intertwined leading to a cascading deadlock. When | |||
this occurred all XCI processing threads and eventually the XCI listener | |||
thread would become blocked waiting to get the current configuration. | |||
20080409 - Version V2-9rc5.18.6 | |||
Enhanced XCI exception handling and logging to provide additional detail. | |||
Added code to explicitely check for zero length files in scanMessagFile(). | |||
Previously a zero length file would cause the CBFR module of the filter | |||
chain to throw an invalid buffer exception. Now if the message file is empty | |||
scanMessageFile() will throw a FileError stating FileEmpty!. | |||
20080407 - Version V2-9rc5.17.6 | |||
Enhanced exception reporting in snfXCImrg | |||
20080405 - Version V2-9rc5.16.6 | |||
Reduced safetly limits on status reports to 100K for status reports and 100K | |||
for samples. Previous values were 10M. Most full sessions from the busiest | |||
systems are < 50K total. | |||
Recoded sendDataTimeout() to break uploads into 512 byte chunks and insert | |||
delays only when a chunk is fragmented. This methodology improves reliability | |||
on Win* systems without any significant penalty on systems that don't need | |||
socket sends() to be in smaller chunks. | |||
Fixed TCPClient::transmit() and TCPHost::transmit() bug where returned byte | |||
count might be -1. Now returned byte counts can only be 0 or more. | |||
20080403 - Version SNF2-9vr5.15.5 | |||
Minor modifications to networking module to better support non-blocking open() | |||
Updated SNFClient with new timing and non-blocking open(). Worst case return | |||
time from SNFClient estimated at 200 seconds (theoretically impossible). No- | |||
connection return time from SNFClient estimated at 20 seconds. | |||
20080326 - Version SNF2-9rc4.15.4 | |||
Refactored snfNETmgr::sync() to consolidate non-blocking io routines. | |||
Added detailed thread status data to XCI listener thread. | |||
Refactored snfNETmgr::sync() to check a Timeout, removed TCPWatchdog. | |||
20080325 - Version SNF2-9rc4.12.4 | |||
Added a "Rulebase Getter" feature as part of the snf_Reloader. When enabled | |||
the Rulebase Getter will launch a user defineable system() call whenever a | |||
new rulebase file is available. The call will be repeated until the condition | |||
is cleared by a successful update of the rulebase file. The Rulebase Getter | |||
will wait a configurable "guard time" between attempts. The default system() | |||
call is "getRulebase" with a guard time of 3 minutes. In most cases this will | |||
launch the provided getRulebase script which should be present in the start | |||
location of SNFServer on most systems. Best practice is to configure the full | |||
path to the update script. The system() call is made in a separate thread so | |||
that if the system() call hangs for some reason only the Rulebase Getter is | |||
stuck. | |||
Improved exception handling/reporting in scanMessageFile(). | |||
Updated scanMessagFile() header injection code to accommodate messages with | |||
no body. Previous version would throw an exception when it could not find an | |||
injection point. The new version makes the injection point byte 0 and puts | |||
the injected headers at the top of the message using it's best guess about the | |||
type of line endings (CRLF or LF) to use. | |||
Updated Networking library to use SO_REUSEADDR by default on listeners. | |||
20080319 - Version SNF2-9rc4.11 | |||
Added IPScan on-off to snfmdplugin.xml. This allows users to turn off the | |||
IPScan feature without editing the Plugins.dat file as was previously | |||
required. The feature can now be enabled or disabled at will by editing the | |||
configuration file. | |||
Added Configuration editor options to snfmdplugin.xml. Previously the built- | |||
in configuration function was hard coded to start notepad with the config | |||
file. Now the system() call made by the ConfigFunc() can be edited in the | |||
configuration file. The configuration file name can be appended to the | |||
command optionally. The default is still to start notepad and append the | |||
configuration file path so that it is loaded automatically. It is hoped that | |||
GUI based configuration editors for the SNF plugin will be built by third | |||
parties and in the mean time folks can now configure their favorite XML file | |||
editor to modify their SNF plugin configuration. | |||
Modified API use fixed shutdown bug - The plugin used to initialize the SNF | |||
scanning engine when the DLL was loaded and would shut it down when the DLL | |||
was unloaded. Now the Startup and Shutdown functions in the MDaemon plugin | |||
API. This ensures that the engine components are started and shutdown in the | |||
proper sequence. | |||
Included new SNFEngine core (excerpts from that change log included). | |||
20080318 - SNF2-9rc1.11.exe Consolidated several mods/fixes | |||
Corrected scan error logging bug. Was posting <s/> now posts <e/>. | |||
Updated scan error logging to be more uniform with non-scan errors. | |||
Developed various script prototypes for postfix integration & automated | |||
updates on win* systems using the new UpdateReady.txt file mechanism. | |||
Fixed a bug in scanMessageFile() where an \n\n style insertion point | |||
would never be detected. | |||
Modified scanMessageFile() header injection to strip <CR> from line ends | |||
when the message file provided does not use them. The line-end style of | |||
the message file is detected while locating the insertion point. If the | |||
insertion point (first blank line) does not use <CR><LF> then the SNF | |||
generated X-Headers are stripped of <CR> in a tight loop before injection. | |||
Enhanced error and exception reporting in SNFMulti.cpp scanMessageFile(). | |||
Enhanced exception handling in networking module. All exceptions now | |||
throw descriptive runtime_error exceptions. | |||
20080306 - SNF2-9rc1.8.exe (FIRST RELEASE CANDIDATE for VERSION 3!) | |||
Added Drilldown Header Directive Functions - When the candidate source IP | |||
comes from a header matching a drilldown directive the IP is marked "Ignore" | |||
in GBUdb and the candidate is no longer eligible to be the source for that | |||
message. This allows SNF to follow the trusted chain of devices (by IP) down | |||
to the actual source of the message. It is handy for ignoring net blocks | |||
because it can match partial IPs but it is designed to allow SNF to learn | |||
it's way through the servers at large ISPs so that the original source for | |||
each message can be evaluated directly. | |||
Added Source Header Directive Functions - This feature allows SNF to acquire | |||
the source IP for a message from a specific header rather than searching | |||
through the Received headers in the message. This is useful when the original | |||
source for a message is not represented in Received headers. For example: | |||
Hotmail places the originating source IP in a special header and does not | |||
provide a Received header for that IP. This feature is protected from abuse | |||
by a "Context" feature which only activates the source header directive when | |||
specific content is found in a specific received header. Using the above | |||
example, this feature can be configured so that a Hotmail source header would | |||
only be read if the top Recieved header contained "hotmail.com [" indicating | |||
that the ptr lookup for the header matched the hotmail domain. Note: When a | |||
source is pulled from a header directive that source is put into a synthetic | |||
Received header and injected into the scanning stream (not the message) as | |||
the first Received header. | |||
Added forced source IP to XCI - It is now possible to "inject" or "force" | |||
the source IP for any message by providing that IP in the XCI request or | |||
directly in a scan...() function call. This allows the calling application | |||
to provide the source IP for a message ahead of any Received headers that | |||
might be in the message. This is useful when the calling application knows | |||
the original source IP for the message but that IP is not represented in | |||
the Received headers and it is not desireable to use the Source Header | |||
Directive mechanism. | |||
Added forced source IP mode to SNFClient - It is now possible to call the | |||
SNFClient utility with an IP4Address using the syntax: | |||
SNFClient -source=12.34.56.78 | |||
The -source mode of SNFClient exercises the forced source IP feature in | |||
the XCI (see above) | |||
Added Status Report features to SNFClient and XCI - It is now possible to | |||
request the latest status.second, status.minute, or status.hour data via | |||
the XCI and SNFClient. The syntax for requesting a status report using the | |||
SNFClient is: | |||
SNFClient -status.second | |||
SNFClient -status.minute | |||
SNFClient -status.hour | |||
In addition to providing status reports the SNFClient in this mode will | |||
return a nonzero value (usually 99) if it is unable to get a status report | |||
from SNFServer. This feature can be used to verify that SNFServer is up | |||
and responding. If SNFServer is OK then the result code returned is 0. | |||
Added result codes to SNFClient -test and XCI IP test functions - The XCI | |||
engine has been upgraded to provide the range value for the IP under test | |||
as well as the symbolic result code associated with that range. This allows | |||
the -test function to provide results that are consistent with the GBUdb | |||
configuration without additional processing: For example, if the IP falls | |||
in the Caution range then the Caution result code will be returned just | |||
as if a message had been scanned with the same IP and no pattern match | |||
occurred. The same is true for Truncate and Black range hits. | |||
Added Timestamp and Command Line Parameter data to SNFClient.exe.err - When | |||
an error occurs with SNFClient that may not appear in the SNFServer logs an | |||
entry is appended to the SNFClient.exe.err file. That in itself is not new. | |||
The new feature is that the entries added to the SNFClient.exe.err file now | |||
include timestamp and command line data to aid in debugging. | |||
Updated the Configuration Log to include all of the current configuration | |||
features and to improve it's readability. | |||
20080207 - SNF2-9b1.7.exe | |||
SYNC Timeout now 2x SYNC Schedule | |||
SNFServer now produces an UpdateReady.txt file when the UTC timestamp on | |||
the SYNC server is newer than the UTC timestamp of the active rulebase. It | |||
is presumed that a suitable update script or program will run periodically | |||
and download a fresh rulebase file if the UpdateReady.txt file is present. | |||
The update script should remove the UpdateReady.txt file when it completes | |||
a successful download of the new rulebase file. | |||
Added available rulebase UTC in status reports <udate utc.../> | |||
Added Automatic path fixup for ending / or \ | |||
Added option to use local time in log rotation <rotation localtime='no'/> | |||
The default is still utc. | |||
20071102 - SNF2-9b1.6.exe | |||
Increased MAX_EVALS from 1024 to 2048. | |||
Adjusted defult range envelopes in snf_engine.xml to be more conservative. | |||
20071017 - Version SNF2-9b1.5 | |||
Added a missing #include directive to the networking.hpp file. The | |||
missing #include was not a factor on Linux and Windows systems but | |||
caused compiler errors on BSD systems. | |||
Corrected a bug in the GBUdb White Range code where any message with a | |||
white range source IP was being forced to the white result code. The | |||
engine now (correctly) only forces the result and records the event when | |||
a black pattern rule was matched and the White Range IP causes that | |||
scan result to be overturned. If the scan result was not a black pattern | |||
match then the original scan result is allowed to pass through. | |||
Corrected a bug in the Header Analysis filter chain module that would | |||
cause the first header in the message to be ignored in some cases. | |||
Corrected an XML log format problem so that <s/> elements are correctly | |||
open ended <s ....> or closed (empty) <s..../> according to whether they | |||
have subordinate elements. | |||
Adjusted the GBUdb header info format. The order of the Confidence | |||
figure and Probabilty figure is now the same as in the XML log files | |||
(C then P). The confidence and probability figures are now preceeded | |||
with c= and p= respectively so that it's easy to tell which is which. | |||
20071009 Version 2-9b1.4 | |||
Tightened up the XCI handler code and removed the watchdog. The watchdog | |||
would restart the listener if there were no connections in 5 minutes. It | |||
was originally added to provide additional stability, however in practice | |||
there have been no "stalled listeners". Also, a stalled listener would | |||
likely be a sign of a different problem that the watchdog would tend to | |||
hide. | |||
Modified and refactored the XCI configuration management code. All XCI config | |||
changes and up-down operations are now handled in a single function except | |||
upon exit from the main XCI thread where XCI_shutdown() is always called. | |||
Added some more detailed exception handling code to the XCI component so that | |||
more data will be logged in the event of an error. | |||
Reviewed and modified the InstallInstructions.txt file. Removed this log | |||
to this separate file. | |||
Modified the snfmdplugin.xml file to properly configure the new features in | |||
the engine. | |||
* Header training directives and new <training/> section. | |||
* XCI interface configuration. | |||
* Tweaks to GBUdb ranges. | |||
* msg-file type configuration (not used in MDaemon, but configured anyway) | |||
---- | |||
Version 2-9a11 (engine a53) | |||
* Enhanced IP extraction from Received headers so that any unexpected bytes | |||
between the [ and ] will force the attempt to be aborted. | |||
* Fix the IP test code so that the IP 0.0.0.0 cannot be the source IP and | |||
cannot be tested. | |||
Version 2-9a11 (engine a52) | |||
* Corrected plug-in log entry logic. Allowed/Rejected tag now comes directly | |||
from the message rejection logic and is accurate in all cases. | |||
Version 2-9a10 (engine a52) | |||
* Corrected a bug in the MessageIPFunc where Ignore flagged IPs would still | |||
cause rejected messages if the statistics were in the Truncate range. Now | |||
messages are rejected in only two cases: | |||
The Flag is _Ugly_ and the rating is _Truncate_ or, the Flag is _Bad_. | |||
Version 2-9a9 (engine a52) | |||
* Adjusted IPtest module in HeaderAnalysis to handle TooManyIPs exception | |||
locally and silently. | |||
* Increased HeaderAnalysis IP limit from 20 to 50. | |||
Version 2-9a9 (engine a51) | |||
* Corrected possible heap corruption bug in EvaulationMatrix Destructors. | |||
* Added trace strings to scanMessage() for tighter panic reporting. | |||
* Added caching to snf_engine Evaluator allocation scheme. | |||
* Added optimizations to snf_engine Evaluator safety checks. | |||
Version 2-9a8 | |||
* Added deep exception handling to Token Matrix objects. | |||
Version 2-9a7 | |||
* Exception handling throughout the engine has been refactored to use std:exception | |||
and to provide additional detail via e.what() | |||
* The plug-in log will now show e.what() data as SNF Debug: whenever an exception | |||
is thrown during a message scan. | |||
Version 2-9a6 | |||
* Adjusted .ctl file path converter to accept either .msg or .tmp paths. | |||
Version 2-9a5 | |||
A lot of new things were learned, updated, and corrected. | |||
* Fixed the "lockup" when the plugin failed to start successfully. The cause of this | |||
appears to be a threading issue associated with DLLs that are being initialized. | |||
If threads are created during the initialization of a DLL, the DLL must succeed! | |||
The threads that are created do not get any cycles until after the DLL is loaded | |||
successfully. As a result, if the initialization process attempts to join() these | |||
threads a deadlock is created. The fix was to allow the SNF plugin initialization | |||
process to succeed in all cases while setting a flag that forces the engine to | |||
be inert if the initialization was not successful. When the DLL is later unloaded | |||
the threads are already running so the join() calls that are part of the engine | |||
cleanup code are able to complete without incident. | |||
* Installed detailed exception handling for the start-up sequence. The plugin can | |||
now report on very specific reasons for failing to initialize properly. | |||
* Fixed a bug in the GBUdbIgnoreList processor where long lines would cause the | |||
remainder of the file not to be read. The line length limit still exists, but | |||
it is now 255 characters which is unlikely to occur and would be considered | |||
incorrect formatting. | |||
* The threading library now includes top-level exception handling to trap any | |||
exception that was not handled by myTask(). Along with this two flags were | |||
added to thread objects: isRunning() and isBad(). isRunning() is true when a | |||
thread object is still active. isBad() is true if the thread failed to start or | |||
an exception escaped myTask(). | |||
* At least one GBUdbIgnoreList entry is now REQUIRED. If the count of IPs from the | |||
GBUdbIgnoreList.txt file is less than 1 (or the file is missing) then the plug-in | |||
will complain and fail to start. | |||
* snf2check.exe has been removed from the distribution for the time being since it | |||
causes some systems to strip the attachment or block the email. This is the same | |||
program that is already on existing SNF systems. |
@@ -0,0 +1,10 @@ | |||
# List of IPs to Ignore on startup | |||
# Each IP in this list is set to Ignore in GBUdb when | |||
# The configuration is loaded. | |||
# Hash mark on the beginning of a line indicates a comment. | |||
# Comments after an IP are also ignored. | |||
# One line per IP. Sorry, no CIDR yet. | |||
# Be sure to list ALL of your gateways :-) | |||
127.0.0.1 # ignore localhost, of course. | |||
@@ -0,0 +1,146 @@ | |||
MDaemon Plugin V2.9rc* (V3) installation instructions | |||
------------------------------------------------------------------------------ | |||
1. Locate your \MDaemon directory (Usually c:\MDaemon) | |||
2. Create the directory \MDaemon\SNF | |||
3. Copy the distribution files to \MDaemon\SNF | |||
4. Edit identity.xml in notepad. | |||
4.1. Replace licensid with your SNF license ID. | |||
4.2. Replace authenticationxx with your SNF authentication code. | |||
5. Adjust/Create your Plugins.dat file (\MDaemon\App\Plugins.dat) | |||
5.1. If you already have a Plugins.dat file | |||
5.1.1. Copy the contents of the Plugins.dat file in the distribution | |||
to the Plugins.dat file you have. | |||
5.1.2. If you have a [Message Sniffer] section in your Plugins.dat | |||
file then make a copy of it (for backup) then remove that | |||
section. (This will disable your previous Message Sniffer | |||
installation) | |||
5.2. If you do not already have a Plugins.dat file | |||
5.2.1. Copy the Plugins.dat file from the distribution to your | |||
\MDaemon\App directory. | |||
6. Copy the snf-groups.cf into \MDaemon\SpamAssassin\rules | |||
7. Download your SNF rulebase file and place it in your SNF directory. | |||
7.1. Once you've signed up for a 30 Day free Trial or purchased a license for | |||
SNF you will receive update notifications via email. These notifications | |||
contain instructions on how to download your rulebase file. You can get | |||
your 30 Day Free Trial started by visiting www.armresearch.com. | |||
7.2. We have included an update script and utilities that you can use to | |||
automate updates to your rulebase file. The SNFServer engine that runs | |||
inside the plugin will produce an UpdateReady.txt file any time the local | |||
rulbase file is older than the latest available update. The included | |||
getRulebase.cmd script checks for this file and uses the open source | |||
wget and gzip utilities to download, validate, and replace your rulebase | |||
file automatically. | |||
7.2.1. Edit the top of the getRulebase.cmd file to establish the correct | |||
working directory, authentication string, and license ID for your | |||
rulebase files. | |||
7.2.2. Verify that the <update-script/> section of your snfmdplugin.xml file | |||
points to the correct location of the getRulebase.cmd script. This new | |||
feature will automatically run the getRulebase.cmd script whenever a | |||
newer rulebase file is available on our servers. | |||
8. Edit the GBUdbIgnoreList.txt file in notepad. | |||
8.1 Add the IP of any gateways you have as well as any systems you | |||
have that send mail through your mail server. | |||
8.2 It is very important to populate your GBUdbIgnoreList if you have | |||
gateways ahead of your mail server or else GBUdb will learn that | |||
those systems are responsible for sending spam! The GBUdb engine | |||
uses the ignore list to determine the actual source IP of the message. | |||
The first IP it sees in the headers that is not on the ignore list | |||
is determined to be the source IP for the message. Since most email | |||
"in the wild" these days are spam, any gateways that are not listed | |||
will be seen to be sending mostly spam - in error, of course. | |||
8.3 You cannot enter network blocks in the GBUdbIgnoreList.txt file. If | |||
you wish to ignore (mark as infrastructure) blocks of IPs then you should | |||
use the <drilldown/> section of the snfmdplugin.xml file to enter | |||
patterns that match the network blocks you want to ignore. For example, | |||
if you want to ignore servers in the 12.34.56.0/24 network block then | |||
you would enter a drilldown rule like: | |||
<drilldown> | |||
... | |||
<received ordinal='0' find='[12.34.56.'/> | |||
The rule tells GBUdb to learn to ignore any IP in the top (ordinal 0) | |||
received header if that header contains the string '[12.34.56.'. Of | |||
course that string will match every IP in the 12.34.56.0/24 class C | |||
block so any servers in that block which deliver mail to the SNF equiped | |||
server will be learned as infrastructure (ignore flag set). | |||
9. Review and adjust your snfmdplugin.xml file | |||
9.1. Check the paths at the top of the file and make sure they are complete and | |||
correct. In most cases the defaults will work, but if you've installed | |||
MDaemon & SNF on a different drive or in a different directory it would | |||
be best to update these paths: | |||
9.1.1. Find/Check <snf><node identity.../> | |||
9.1.2. Find/Check <snf><node><paths><log path.../> | |||
9.1.3. Find/Check <snf><node><paths><rulebase path.../> | |||
9.1.4. Find/Check <snf><node><paths><workspace path.../> | |||
9.2. If you have any addresses where people legitimately send spam such as an | |||
abuse reporting address or support address then you should enter that | |||
address into the <snf><node><gbudb><training><bypass/> section of the | |||
snfmdplugin.xml file. For example an abuse reporting address might look | |||
like this: | |||
<bypass> | |||
... | |||
<header name='To:' find='spam@example.com'/> | |||
The rule tells GBUdb to bypass it's training mechanism if it finds a | |||
'To:' header in a message that contains 'spam@example.com'. This should | |||
prevent customer's IPs from being learned as spam sources when they send | |||
messages to spam@example.com. | |||
9.3. Your system practices and policies may require additional rules in order | |||
to get the best performance from the GBUdb system. For more information | |||
please check out www.armresearch.com, support@armresearch.com, and our | |||
community list sniffer@sortmonster.com. | |||
10. Restart MDaemon. | |||
11. Verify the SNF plugin is installed | |||
11.1. In the plug-ins log tab you should see: | |||
Attempting to load 'SNF' plugin | |||
* ConfigFunc: ConfigFunc@4 (Ok, ready to use) | |||
* StartupFunc: Startup@4 (Ok, ready to use) | |||
* ShutdownFunc: Shutdown@4 (Ok, ready to use) | |||
* PreMessageFunc: (NULL) | |||
* PostMessageFunc: MessageFunc@8 (Ok, ready to use) | |||
* SMTPMessageFunc: MessageIPFunc@8 (Ok, ready to use) | |||
* SMTPMessageFunc2: (NULL) | |||
* SMTPMessageFunc3: (NULL) | |||
* DomainPOPMessageFunc: (NULL) | |||
* MultiPOPMessageFunc: (NULL) | |||
* Result: success (plugin DLL loaded in slot 0) | |||
---------- | |||
SNF plugin is starting up | |||
SNFMulti Engine Version 2.9rc11 Build: Mar 20 2008 15:18:30 | |||
SNF MDaemon Plugin Version 2-9rc4 Build: Mar 20 2008 15:17:20 | |||
SNF Config: C:\MDaemon\SNF\SNFMDPlugin.xml | |||
---------- | |||
Note that the slot may be different if you have other plugins. | |||
11.2. When your system processes a message you should see something like: | |||
SNF MessageScan: c:\mdaemon\queues\local\md50000000039.msg, Result=0 | |||
If you have a valid AntiVirus for MDaemon license you should also see | |||
a line similar to this: | |||
SNF IPScan: C:\MDaemon\Queues\Inbound\md50000000029.msg, 192.168.0.102, {Ugly, p=-1, c=0.303425, Normal} Allowed. | |||
11.3. In your messages you should see some new headers similar to: | |||
X-MessageSniffer-GBUdb-Result: 0, 192.168.0.102, Ugly -1 0.303425 Source Normal | |||
X-MessageSniffer-Scan-Result: 0 | |||
X-MessageSniffer-Patterns: | |||
0-0-0-998-c |
@@ -0,0 +1,11 @@ | |||
[SNF] | |||
MenuText=Configure SNF Plug-in | |||
Enable=Yes | |||
DllPath=c:\MDaemon\SNF\snfmdplugin.dll | |||
StartupFuncName=Startup@4 | |||
ConfigFuncName=ConfigFunc@4 | |||
PostMessageFuncName=MessageFunc@8 | |||
SMTPMessageFuncName=MessageIPFunc@8 | |||
ShutdownFuncName=Shutdown@4 | |||
PluginDoesAllLogging=No | |||
NonAuthOnly=Yes |
@@ -0,0 +1,182 @@ | |||
SNFClient Readme | |||
Command line client for SNF. This utility formats and processes SNF_XCI | |||
requests through the SNF Engine working on the local machine. In general | |||
this utility can be used as a replacement for the earlier SNF command | |||
line scanner. It is also useful for other uses such as debugging and | |||
communicating with GBUdb. | |||
Note: Unlike prior versions of SNF, this command line utility does not | |||
need to be "branded" (renamed for the SNF license id). | |||
_________ | |||
Help Mode | |||
SNFClient.exe | |||
When called with no command line parameters the utility produces | |||
help and version information. | |||
__________ | |||
Debug Mode | |||
SNFDebugClient.exe | |||
When "debug" or "Debug" appears in the path to the program name | |||
or if the program's name is altered to include the word "debug" or | |||
"Debug" then the program will produce additional information about | |||
it's operation to aid in debugging problems. This includes the | |||
entire raw SNF_XCI request and response. | |||
__________________ | |||
Message Scan Modes | |||
These modes are used to scan email message files (the data part of | |||
smtp). This utility can be used as a drop-in replacement for previous | |||
verions of SNF (Message Sniffer) for scanning messages. However, this | |||
new version does not need to be "branded" (renamed for the license id) | |||
and will ignore the authentication string if it is provided. Also, | |||
since the newer version of SNF uses a client-server model and not a | |||
peer-server model, there is no need for a "persistent" mode. | |||
If "persistent" is passed to this utility on the command line as it | |||
would be used in prior versions of SNF then it will be treated like | |||
a file name and the scan will normally fail since a file named | |||
"persistent" is not likely to exist. | |||
SNFClient.exe <FileNameToScan> | |||
Scan Mode: Scans <FileNameToScan> and returns a result code. | |||
SNFClient.exe <authenticationxx> <FileNameToScan> | |||
Compatibility Mode: Ignores <authenticationxx> then scans the | |||
<FileNameToScan> and returns a result code. This mode provides | |||
drop-in compatibility with previous versions of SNF. | |||
SNFClient.exe -xhdr <FileNameToScan> | |||
XHeader Mode: Scans <FileNameToScan> and returns the result. Also | |||
outputs the contents of the X-Headers created by the SNF engine. If | |||
the SNF engine is configured to inject these headers then they will | |||
also have been injected into the <FileNameToScan>. | |||
The SNF Engine can be configured to provide the X-Headers only to | |||
the API without injecting them. In this case the XHeader Mode will | |||
display the X-Headers that would be injected, but they will not | |||
have been injected into the <FileNameToScan>. | |||
If the SNF Engine is configured not to produce X-Headers (none) then | |||
the XHeader Mode will not produce X-Headers because they will not | |||
have been generated by the engine. | |||
(note: -xhdr and -source options can be combined) | |||
SNFClient.exe -source=<IP4Address> <FileNameToScan> | |||
Source-IP Mode: Scans <FileNameToScan> and returns the result. The | |||
provided source IP is injected into the scan as the first Received | |||
header so that the scanning engine will presume the IP is the source | |||
of the message. This allows you to pre-define the source IP for the | |||
message when there is no other received header or when the received | |||
headers may be incorrect or may not present the actual source of | |||
the message. | |||
(note: -xhdr and -source options can be combined) | |||
_____________________________ | |||
SNFServer Status Report Modes | |||
SNFClient.exe -status.second | |||
SNFClient.exe -status.minute | |||
SNFClient.exe -status.hour | |||
This mode returns the latest posted status report as indicated. | |||
Normally these status reports are also posted to files in the | |||
SNFServer workspace. | |||
In this mode the SNFClient will return a result code (error level) | |||
of 0 when the request is successful and 99 (or some nonzero value) | |||
when the request is not successful. This allows the SNFClient to | |||
be used to verify that the SNFServer is running. | |||
Note: In most other modes the SNFClient returns a fail-safe 0 | |||
result code to avoid tagging messages as spam when there are errors. | |||
________________________ | |||
XCI Server Command Modes | |||
These features will expand as needed in later versions. | |||
SNFClient.exe -shutdown | |||
If the SNF Engine is running in an application that accepts SNF_XCI | |||
server commands then this mode will send that command. The shutdown | |||
command may have no effect if the application does not use the SNF_XCI | |||
server commnand interface or does not recognize the command. | |||
___________ | |||
GBUdb Modes | |||
These modes are used to communicate with the GBUdb system on the | |||
local node. It is possible to test (read out) an IP record or make | |||
any of a number of changes to IP data in the GBUdb. | |||
SNFClient.exe -test <IP4Address> | |||
Returns the current GBUdb statistics for the <IP4Address> | |||
SNFClient also returns a result code that matches the GBUdb range | |||
for the tested IP. These ranges are defined in the SNFServer | |||
configuration file. By default they are: | |||
20 - Truncate | |||
63 - Black | |||
40 - Caution | |||
0 - Normal | |||
SNFClient.exe -set <IP4Address> <flag> <bad> <good> | |||
Creates or updates the data for <IP4Address> as provided. The | |||
<IP4Address> must be provided as well as at least one of | |||
<flag>, <bad>, and <good>. If <flag>, <bad>, or <good> are | |||
to be left unchanged then they should be entered as a dash "-". | |||
Examples: | |||
Set all data for an IP. The flag will be "ugly", the bad count | |||
will be 0 and the good count will be 1000. | |||
SNFClient.exe -set 12.34.56.78 Ugly 0 1000 | |||
Set the flag to "ignore" and do not change the counts. | |||
SNFClient.exe -set 12.34.56.78 ignore - - | |||
Set the good count to 400 and do not change anything else. | |||
SNFClient.exe -set 12.34.56.78 - - 400 | |||
SNFClient.exe -good <IP4Address> | |||
Creates or updates statistics for the <IP4Address>. Increases the | |||
good count by one. (Record a good event) | |||
SNFClient.exe -bad <IP4Address> | |||
Creates or updates statistics for the <IP4Address>. Increases the | |||
bad count by one. (Record a bad event) | |||
SNFClient.exe -drop <IP4Address> | |||
Removes all local data for the <IP4Address>. Anything the local | |||
system "knows" about the IP is forgotten. Next time the IP is | |||
encountered it will be treated as new. | |||
____________________ | |||
For More Information | |||
See www.armresearch.com | |||
Copyright (C) 2007-2008 Arm Research Labs, LLC. | |||
@@ -0,0 +1,47 @@ | |||
@ECHO OFF | |||
SETLOCAL | |||
REM ----- Edit This Section -------- | |||
SET SNIFFER_PATH=\mdaemon\snf | |||
SET AUTHENTICATION=authenticationxx | |||
SET LICENSE_ID=licensid | |||
REM -------------------------------- | |||
CD /d %SNIFFER_PATH% | |||
if not exist UpdateReady.txt GOTO DONE | |||
if exist UpdateReady.lck GOTO DONE | |||
:DOWNLOAD | |||
COPY UpdateReady.txt UpdateReady.lck | |||
wget http://www.sortmonster.net/Sniffer/Updates/%LICENSE_ID%.snf -O %LICENSE_ID%.new.gz --header=Accept-Encoding:gzip --http-user=sniffer --http-passwd=ki11sp8m | |||
if exist %LICENSE_ID%.new.gz gzip -d -f %LICENSE_ID%.new.gz | |||
snf2check.exe %LICENSE_ID%.new %AUTHENTICATION% | |||
if errorlevel 1 goto CLEANUP | |||
if exist %LICENSE_ID%.old del %LICENSE_ID%.old | |||
rename %LICENSE_ID%.snf %LICENSE_ID%.old | |||
rename %LICENSE_ID%.new %LICENSE_ID%.snf | |||
if exist UpdateReady.txt del UpdateReady.txt | |||
if exist UpdateReady.lck del UpdateReady.lck | |||
:CLEANUP | |||
if exist %LICENSE_ID%.new del %LICENSE_ID%.new | |||
if exist UpdateReady.lck del UpdateReady.lck | |||
:DONE | |||
ENDLOCAL | |||
@@ -0,0 +1 @@ | |||
<snf><identity licenseid='licensid' authentication='authenticationxx'/></snf> |
@@ -0,0 +1,80 @@ | |||
## Basic rules for detecting Message Sniffer header emissions | |||
## so that they can be given scores in subsequent SpamAssassin | |||
## scanning. Modify the scores and headers as needed for your | |||
## system. | |||
score SNF_IPTRUNCATE 10 | |||
describe SNF_IPTRUNCATE IP Source consistently sends spam | |||
header SNF_IPTRUNCATE X-MessageSniffer-Scan-Result =~ /20/ | |||
score SNF_IPCAUTION 3 | |||
describe SNF_IPCAUTION New IP source mixed scan results | |||
header SNF_IPCAUTION X-MessageSniffer-Scan-Result =~ /40/ | |||
score SNF_IPBLACK 4 | |||
describe SNF_IPBLACK Static IP rules and GBUdb Black | |||
header SNF_IPBLACK X-MessageSniffer-Scan-Result =~ /63/ | |||
score SNF_OBFUSCATION 5 | |||
describe SNF_OBFUSCATION Obfuscation detection | |||
header SNF_OBFUSCATION X-MessageSniffer-Scan-Result =~ /62/ | |||
score SNF_ABSTRACT 5 | |||
describe SNF_ABSTRACT Abstracted spam patterns | |||
header SNF_ABSTRACT X-MessageSniffer-Scan-Result =~ /61/ | |||
score SNF_GENERAL 5 | |||
describe SNF_GENERAL General spam content - unclassified | |||
header SNF_GENERAL X-MessageSniffer-Scan-Result =~ /60/ | |||
score SNF_GAMBLE 5 | |||
describe SNF_GAMBLE Gambling and Casino spam patterns | |||
header SNF_GAMBLE X-MessageSniffer-Scan-Result =~ /59/ | |||
score SNF_DEBT 5 | |||
describe SNF_DEBT Debt and Credit offer spam patterns | |||
header SNF_DEBT X-MessageSniffer-Scan-Result =~ /58/ | |||
score SNF_GETRICH 5 | |||
describe SNF_GETRICH Home Biz, Stock Push, get rich quick | |||
header SNF_GETRICH X-MessageSniffer-Scan-Result =~ /57/ | |||
score SNF_TONER 5 | |||
describe SNF_TONER Ink and Toner offer spam patterns | |||
header SNF_TONER X-MessageSniffer-Scan-Result =~ /56/ | |||
score SNF_MALWARE 5 | |||
describe SNF_MALWARE Virus, worm, and exploit patterns | |||
header SNF_MALWARE X-MessageSniffer-Scan-Result =~ /55/ | |||
score SNF_ADULT 5 | |||
describe SNF_ADULT Porn and Adult spam patterns | |||
header SNF_ADULT X-MessageSniffer-Scan-Result =~ /54/ | |||
score SNF_SCAM 5 | |||
describe SNF_SCAM Phishing, 419, and other scam patterns | |||
header SNF_SCAM X-MessageSniffer-Scan-Result =~ /53/ | |||
score SNF_SNAKEOIL 5 | |||
describe SNF_SNAKEOIL Drugs, diet aids, health scams | |||
header SNF_SNAKEOIL X-MessageSniffer-Scan-Result =~ /52/ | |||
score SNF_SPAMWARE 5 | |||
describe SNF_SPAMWARE Spamming tools and spam hosting offers | |||
header SNF_SPAMWARE X-MessageSniffer-Scan-Result =~ /51/ | |||
score SNF_DATATHEFT 5 | |||
describe SNF_DATATHEFT Movies, software, unlimited downloads | |||
header SNF_DATATHEFT X-MessageSniffer-Scan-Result =~ /50/ | |||
score SNF_AVPUSH 5 | |||
describe SNF_AVPUSH Antivirus software push | |||
header SNF_AVPUSH X-MessageSniffer-Scan-Result =~ /49/ | |||
score SNF_INSURANCE 5 | |||
describe SNF_INSURANCE Insurance offer patterns | |||
header SNF_INSURANCE X-MessageSniffer-Scan-Result =~ /48/ | |||
score SNF_TRAVEL 5 | |||
describe SNF_TRAVEL Travel offer patterns | |||
header SNF_TRAVEL X-MessageSniffer-Scan-Result =~ /47/ |
@@ -0,0 +1,156 @@ | |||
<!-- SNFMulti V3.0 Configuration File, Setup: Typical of MDaemon Plugin --> | |||
<!-- http://www.armresearch.com/support/articles/software/snfServer/config/snfEngine.jsp --> | |||
<snf> | |||
<node identity='/MDaemon/SNF/identity.xml'> | |||
<paths> | |||
<log path='/MDaemon/SNF/'/> | |||
<rulebase path='/MDaemon/SNF/'/> | |||
<workspace path='/MDaemon/SNF/'/> | |||
</paths> | |||
<logs> | |||
<rotation localtime='no'/> | |||
<status> | |||
<second log='yes' append='no'/> | |||
<minute log='yes' append='no'/> | |||
<hour log='no' append='no'/> | |||
</status> | |||
<scan> | |||
<identifier force-message-id='no'/> | |||
<classic mode='none' rotate='no' matches='none'/> | |||
<xml mode='file' rotate='yes' matches='all' performance='yes' gbudb='yes'/> | |||
<xheaders> | |||
<output mode='inject'/> | |||
<version on-off='off'>X-MessageSniffer-Version</version> | |||
<license on-off='off'>X-MessageSniffer-License</license> | |||
<rulebase on-off='off'>X-MessageSniffer-RulebaseUTC</rulebase> | |||
<identifier on-off='off'>X-MessageSniffer-Identifier</identifier> | |||
<gbudb on-off='on'>X-MessageSniffer-GBUdb-Result</gbudb> | |||
<result on-off='on'>X-MessageSniffer-Scan-Result</result> | |||
<matches on-off='on'>X-MessageSniffer-Patterns</matches> | |||
<black on-off='off'>X-MessageSniffer-Spam: Yes</black> | |||
<white on-off='off'>X-MessageSniffer-White: Yes</white> | |||
<clean on-off='off'>X-MessageSniffer-Clean: Yes</clean> | |||
<symbol on-off='off' n='0'>X-MessageSniffer-SNF-Group: OK</symbol> | |||
<symbol on-off='off' n='20'>X-MessageSniffer-SNF-Group: Truncated</symbol> | |||
<symbol on-off='off' n='40'>X-MessageSniffer-SNF-Group: Caution</symbol> | |||
<symbol on-off='off' n='63'>X-MessageSniffer-SNF-Group: Black</symbol> | |||
<symbol on-off='off' n='62'>X-MessageSniffer-SNF-Group: Obfuscation</symbol> | |||
<symbol on-off='off' n='61'>X-MessageSniffer-SNF-Group: Abstract</symbol> | |||
<symbol on-off='off' n='60'>X-MessageSniffer-SNF-Group: General</symbol> | |||
<symbol on-off='off' n='59'>X-MessageSniffer-SNF-Group: Casinos-Gambling</symbol> | |||
<symbol on-off='off' n='58'>X-MessageSniffer-SNF-Group: Debt-Credit</symbol> | |||
<symbol on-off='off' n='57'>X-MessageSniffer-SNF-Group: Get-Rich</symbol> | |||
<symbol on-off='off' n='56'>X-MessageSniffer-SNF-Group: Ink-Toner</symbol> | |||
<symbol on-off='off' n='55'>X-MessageSniffer-SNF-Group: Malware</symbol> | |||
<symbol on-off='off' n='54'>X-MessageSniffer-SNF-Group: Porn-Dating-Adult</symbol> | |||
<symbol on-off='off' n='53'>X-MessageSniffer-SNF-Group: Scam-Phishing</symbol> | |||
<symbol on-off='off' n='52'>X-MessageSniffer-SNF-Group: Snake-Oil</symbol> | |||
<symbol on-off='off' n='51'>X-MessageSniffer-SNF-Group: Spamware</symbol> | |||
<symbol on-off='off' n='50'>X-MessageSniffer-SNF-Group: Media-Theft</symbol> | |||
<symbol on-off='off' n='49'>X-MessageSniffer-SNF-Group: AV-Push</symbol> | |||
<symbol on-off='off' n='48'>X-MessageSniffer-SNF-Group: Insurance</symbol> | |||
<symbol on-off='off' n='47'>X-MessageSniffer-SNF-Group: Travel</symbol> | |||
</xheaders> | |||
</scan> | |||
</logs> | |||
<network> | |||
<sync secs='30' host='sync.messagesniffer.net' port='25'/> | |||
<update-script on-off='on' call='/MDaemon/SNF/getRulebase.cmd' guard-time='180'/> | |||
</network> | |||
<xci on-off='on' port='9001'/> | |||
<gbudb> | |||
<database> | |||
<condense minimum-seconds-between='600'> | |||
<time-trigger on-off='on' seconds='86400'/> | |||
<posts-trigger on-off='off' posts='1200000'/> | |||
<records-trigger on-off='off' records='600000'/> | |||
<size-trigger on-off='on' megabytes='150'/> | |||
</condense> | |||
<checkpoint on-off='on' secs='3600'/> | |||
</database> | |||
<regions> | |||
<white on-off='on' symbol='0'> | |||
<edge probability='-1.0' confidence='0.4'/> | |||
<edge probability='-0.8' confidence='1.0'/> | |||
<panic on-off='on' rule-range='1000'/> | |||
</white> | |||
<caution on-off='on' symbol='40'> | |||
<edge probability='0.4' confidence='0.0'/> | |||
<edge probability='0.8' confidence='0.5'/> | |||
</caution> | |||
<black on-off='on' symbol='63'> | |||
<edge probability='0.8' confidence='0.2'/> | |||
<edge probability='0.8' confidence='1.0'/> | |||
<truncate on-off='on' probability='0.9' peek-one-in='5' symbol='20'/> | |||
<sample on-off='on' probability='0.8' grab-one-in='5' passthrough='no' passthrough-symbol='0'/> | |||
</black> | |||
</regions> | |||
<training on-off='on'> | |||
<bypass> | |||
<!-- <header name='To:' find='spam@example.com'/> --> | |||
<!-- <header name='Received:' ordinal='1' find='friendlyhost.com'/> --> | |||
</bypass> | |||
<drilldown> | |||
<!-- <received ordinal='0' find='[12.34.56.'/> where we want to ignore 12.34.56.0/24 --> | |||
<!-- <received ordinal='0' find='mixed-source.com'/> --> | |||
<!-- <received ordinal='1' find='mixed-source-internal.com'/> --> | |||
</drilldown> | |||
<source> | |||
<!-- <header name='X-Use-This-Source:' received='mixedsource.com [' ordinal='0' /> --> | |||
<!-- <header name='X-Originating-IP:' received='hotmail.com [' ordinal='0' /> --> | |||
</source> | |||
<white> | |||
<result code='1'/> | |||
<!-- <header name='Received:' ordinal='0' find='.friendlyhost.com'/> --> | |||
</white> | |||
</training> | |||
</gbudb> | |||
<rule-panics> | |||
<!-- | |||
<rule id='123456'/> | |||
<rule id='123457'/> | |||
--> | |||
</rule-panics> | |||
<!-- Platform Specific Configuration --> | |||
<platform> | |||
<mdaemon> | |||
<ip-test on-off='on'/> | |||
<configurator command='start notepad' append-path='yes'/> | |||
</mdaemon> | |||
</platform> | |||
<msg-file type='rfc822'/> | |||
</node> | |||
</snf> | |||
@@ -0,0 +1,4 @@ | |||
Included with this distribution are the open-source "wget" and "gzip" files. They are | |||
used in getRulebase.bat to download and decompress rulebase files. The "wget" and "gzip" | |||
utilities included here came from http://unxutils.sourceforge.net/ and are included only | |||
for your convenience. |
@@ -0,0 +1,449 @@ | |||
SNF MDaemon Plugin Change Log... | |||
------------------------------------------------------------------------------ | |||
20080626 - Version 3.0, It's official. | |||
Changed build information. | |||
Removed extraneous comments from configuration file. | |||
20080524 - Version V2-9rc6.25.7 | |||
Optimized networking library for additional speed & stability by moving | |||
receive buffer allocation from heap to stack (automatic). | |||
Optimized timing parameters in SNFClient for improved speed. Polling dealys | |||
are now reduced to 10ms from 30ms. | |||
Removed speed-bug in SNFClient, 100ms guard time between retries was always | |||
executed after an attempt (even a successful attempt). The guard time is now | |||
condition and only fires on unsuccessful attempts. | |||
Updated XCI server logic to ensure non-blocking sockets for clients in all | |||
socket implementations. | |||
20080424 - Version V2-9rc6.24.6 | |||
Refactored snfScanData.clear() to reduce heap work and fragments. | |||
Added mutex to scanMessageFile() entry point just in case some app attempts to | |||
put multiple threads through a single engine handler. scanMessage() is already | |||
protected and fully wraped by the new scanMessageFile() mutex. | |||
Added non-specific runtime exception handling to XHDR injection code. | |||
Added 2 retries w/ 300ms delay to remove original message in XHDR inject code. | |||
If remove fails after 3 attempts the injector throws. | |||
Added 2 retries w/ 300ms delay to rename temp file to msg in XHDR inject code. | |||
If rename fails after 3 attempts the injector throws. | |||
Added IPTest logging. | |||
20080416 - Version V2-9rc5.23.6 | |||
Fixed bug where SNCY open() would fail on some Win* platforms with | |||
WSAEINVAL instead of the standard EINPROGRESS or EALREADY which were expected. | |||
Also added WSAEWOULDBLOCK to cover other "ambiguities" in windows sockets | |||
implementations. InProgress() on Win* now test for any of: | |||
WSAEINPROGRESS, WSAEALREADY, WSAEWOULDBLOCK, WSAEINVAL | |||
20080413 - Version V2-9rc5.22.6 | |||
Fixed bug in TCPHost.open() where EALREADY was not counted as a version of | |||
EINPROGRESS. This would cause open() to throw an unnecessary exception when | |||
an open() required extra time. | |||
20080413 - Version V2-9rc5.21.6 | |||
Extended timeout for SYNC session open() to the full session length. This way | |||
if a session takes a long time to open it still has a shot at success. | |||
20080411 - Version V2-9rc5.20.6 | |||
Adjusted snfNETmgr to use non-blocking open in SYNC sessions. Open timeout | |||
is 1/3 of the session timeout. Session timeout is 2 * Session pacing. Open | |||
polling uses golden spiral delay from 10ms to 340ms. | |||
20080410 - Version V2-9rc5.19.6 | |||
Adjusted XCI manager to use new snfCFGPacket paradigm in checkCFG(). | |||
Adjusted snf_RulebaseHandler::addRulePanic() to use MyMutex and eliminated | |||
the AutoPanicMutex and waiting scheme. | |||
Refactored scanMessage() to use a ScopeMutex() rather than lock()/unlock(). | |||
Refactored scanMessage() to use MyCFGPacket.isRulePanic() test. | |||
Redesigned snfCFGPacket handling to automate grab() / drop() functions. | |||
Fixed lock-up bug: Redesigned AutoPanic posting and checking mechanisms to | |||
eliminate potential dead-lock condition. Under some conditions a precisely | |||
timed auto-panic posting could cause the RulebaesHandler mutex and the | |||
AutoPanicMutex to become intertwined leading to a cascading deadlock. When | |||
this occurred all XCI processing threads and eventually the XCI listener | |||
thread would become blocked waiting to get the current configuration. | |||
20080409 - Version V2-9rc5.18.6 | |||
Enhanced XCI exception handling and logging to provide additional detail. | |||
Added code to explicitely check for zero length files in scanMessagFile(). | |||
Previously a zero length file would cause the CBFR module of the filter | |||
chain to throw an invalid buffer exception. Now if the message file is empty | |||
scanMessageFile() will throw a FileError stating FileEmpty!. | |||
20080407 - Version V2-9rc5.17.6 | |||
Enhanced exception reporting in snfXCImrg | |||
20080405 - Version V2-9rc5.16.6 | |||
Reduced safetly limits on status reports to 100K for status reports and 100K | |||
for samples. Previous values were 10M. Most full sessions from the busiest | |||
systems are < 50K total. | |||
Recoded sendDataTimeout() to break uploads into 512 byte chunks and insert | |||
delays only when a chunk is fragmented. This methodology improves reliability | |||
on Win* systems without any significant penalty on systems that don't need | |||
socket sends() to be in smaller chunks. | |||
Fixed TCPClient::transmit() and TCPHost::transmit() bug where returned byte | |||
count might be -1. Now returned byte counts can only be 0 or more. | |||
20080403 - Version SNF2-9vr5.15.5 | |||
Minor modifications to networking module to better support non-blocking open() | |||
Updated SNFClient with new timing and non-blocking open(). Worst case return | |||
time from SNFClient estimated at 200 seconds (theoretically impossible). No- | |||
connection return time from SNFClient estimated at 20 seconds. | |||
20080326 - Version SNF2-9rc4.15.4 | |||
Refactored snfNETmgr::sync() to consolidate non-blocking io routines. | |||
Added detailed thread status data to XCI listener thread. | |||
Refactored snfNETmgr::sync() to check a Timeout, removed TCPWatchdog. | |||
20080325 - Version SNF2-9rc4.12.4 | |||
Added a "Rulebase Getter" feature as part of the snf_Reloader. When enabled | |||
the Rulebase Getter will launch a user defineable system() call whenever a | |||
new rulebase file is available. The call will be repeated until the condition | |||
is cleared by a successful update of the rulebase file. The Rulebase Getter | |||
will wait a configurable "guard time" between attempts. The default system() | |||
call is "getRulebase" with a guard time of 3 minutes. In most cases this will | |||
launch the provided getRulebase script which should be present in the start | |||
location of SNFServer on most systems. Best practice is to configure the full | |||
path to the update script. The system() call is made in a separate thread so | |||
that if the system() call hangs for some reason only the Rulebase Getter is | |||
stuck. | |||
Improved exception handling/reporting in scanMessageFile(). | |||
Updated scanMessagFile() header injection code to accommodate messages with | |||
no body. Previous version would throw an exception when it could not find an | |||
injection point. The new version makes the injection point byte 0 and puts | |||
the injected headers at the top of the message using it's best guess about the | |||
type of line endings (CRLF or LF) to use. | |||
Updated Networking library to use SO_REUSEADDR by default on listeners. | |||
20080319 - Version SNF2-9rc4.11 | |||
Added IPScan on-off to snfmdplugin.xml. This allows users to turn off the | |||
IPScan feature without editing the Plugins.dat file as was previously | |||
required. The feature can now be enabled or disabled at will by editing the | |||
configuration file. | |||
Added Configuration editor options to snfmdplugin.xml. Previously the built- | |||
in configuration function was hard coded to start notepad with the config | |||
file. Now the system() call made by the ConfigFunc() can be edited in the | |||
configuration file. The configuration file name can be appended to the | |||
command optionally. The default is still to start notepad and append the | |||
configuration file path so that it is loaded automatically. It is hoped that | |||
GUI based configuration editors for the SNF plugin will be built by third | |||
parties and in the mean time folks can now configure their favorite XML file | |||
editor to modify their SNF plugin configuration. | |||
Modified API use fixed shutdown bug - The plugin used to initialize the SNF | |||
scanning engine when the DLL was loaded and would shut it down when the DLL | |||
was unloaded. Now the Startup and Shutdown functions in the MDaemon plugin | |||
API. This ensures that the engine components are started and shutdown in the | |||
proper sequence. | |||
Included new SNFEngine core (excerpts from that change log included). | |||
20080318 - SNF2-9rc1.11.exe Consolidated several mods/fixes | |||
Corrected scan error logging bug. Was posting <s/> now posts <e/>. | |||
Updated scan error logging to be more uniform with non-scan errors. | |||
Developed various script prototypes for postfix integration & automated | |||
updates on win* systems using the new UpdateReady.txt file mechanism. | |||
Fixed a bug in scanMessageFile() where an \n\n style insertion point | |||
would never be detected. | |||
Modified scanMessageFile() header injection to strip <CR> from line ends | |||
when the message file provided does not use them. The line-end style of | |||
the message file is detected while locating the insertion point. If the | |||
insertion point (first blank line) does not use <CR><LF> then the SNF | |||
generated X-Headers are stripped of <CR> in a tight loop before injection. | |||
Enhanced error and exception reporting in SNFMulti.cpp scanMessageFile(). | |||
Enhanced exception handling in networking module. All exceptions now | |||
throw descriptive runtime_error exceptions. | |||
20080306 - SNF2-9rc1.8.exe (FIRST RELEASE CANDIDATE for VERSION 3!) | |||
Added Drilldown Header Directive Functions - When the candidate source IP | |||
comes from a header matching a drilldown directive the IP is marked "Ignore" | |||
in GBUdb and the candidate is no longer eligible to be the source for that | |||
message. This allows SNF to follow the trusted chain of devices (by IP) down | |||
to the actual source of the message. It is handy for ignoring net blocks | |||
because it can match partial IPs but it is designed to allow SNF to learn | |||
it's way through the servers at large ISPs so that the original source for | |||
each message can be evaluated directly. | |||
Added Source Header Directive Functions - This feature allows SNF to acquire | |||
the source IP for a message from a specific header rather than searching | |||
through the Received headers in the message. This is useful when the original | |||
source for a message is not represented in Received headers. For example: | |||
Hotmail places the originating source IP in a special header and does not | |||
provide a Received header for that IP. This feature is protected from abuse | |||
by a "Context" feature which only activates the source header directive when | |||
specific content is found in a specific received header. Using the above | |||
example, this feature can be configured so that a Hotmail source header would | |||
only be read if the top Recieved header contained "hotmail.com [" indicating | |||
that the ptr lookup for the header matched the hotmail domain. Note: When a | |||
source is pulled from a header directive that source is put into a synthetic | |||
Received header and injected into the scanning stream (not the message) as | |||
the first Received header. | |||
Added forced source IP to XCI - It is now possible to "inject" or "force" | |||
the source IP for any message by providing that IP in the XCI request or | |||
directly in a scan...() function call. This allows the calling application | |||
to provide the source IP for a message ahead of any Received headers that | |||
might be in the message. This is useful when the calling application knows | |||
the original source IP for the message but that IP is not represented in | |||
the Received headers and it is not desireable to use the Source Header | |||
Directive mechanism. | |||
Added forced source IP mode to SNFClient - It is now possible to call the | |||
SNFClient utility with an IP4Address using the syntax: | |||
SNFClient -source=12.34.56.78 | |||
The -source mode of SNFClient exercises the forced source IP feature in | |||
the XCI (see above) | |||
Added Status Report features to SNFClient and XCI - It is now possible to | |||
request the latest status.second, status.minute, or status.hour data via | |||
the XCI and SNFClient. The syntax for requesting a status report using the | |||
SNFClient is: | |||
SNFClient -status.second | |||
SNFClient -status.minute | |||
SNFClient -status.hour | |||
In addition to providing status reports the SNFClient in this mode will | |||
return a nonzero value (usually 99) if it is unable to get a status report | |||
from SNFServer. This feature can be used to verify that SNFServer is up | |||
and responding. If SNFServer is OK then the result code returned is 0. | |||
Added result codes to SNFClient -test and XCI IP test functions - The XCI | |||
engine has been upgraded to provide the range value for the IP under test | |||
as well as the symbolic result code associated with that range. This allows | |||
the -test function to provide results that are consistent with the GBUdb | |||
configuration without additional processing: For example, if the IP falls | |||
in the Caution range then the Caution result code will be returned just | |||
as if a message had been scanned with the same IP and no pattern match | |||
occurred. The same is true for Truncate and Black range hits. | |||
Added Timestamp and Command Line Parameter data to SNFClient.exe.err - When | |||
an error occurs with SNFClient that may not appear in the SNFServer logs an | |||
entry is appended to the SNFClient.exe.err file. That in itself is not new. | |||
The new feature is that the entries added to the SNFClient.exe.err file now | |||
include timestamp and command line data to aid in debugging. | |||
Updated the Configuration Log to include all of the current configuration | |||
features and to improve it's readability. | |||
20080207 - SNF2-9b1.7.exe | |||
SYNC Timeout now 2x SYNC Schedule | |||
SNFServer now produces an UpdateReady.txt file when the UTC timestamp on | |||
the SYNC server is newer than the UTC timestamp of the active rulebase. It | |||
is presumed that a suitable update script or program will run periodically | |||
and download a fresh rulebase file if the UpdateReady.txt file is present. | |||
The update script should remove the UpdateReady.txt file when it completes | |||
a successful download of the new rulebase file. | |||
Added available rulebase UTC in status reports <udate utc.../> | |||
Added Automatic path fixup for ending / or \ | |||
Added option to use local time in log rotation <rotation localtime='no'/> | |||
The default is still utc. | |||
20071102 - SNF2-9b1.6.exe | |||
Increased MAX_EVALS from 1024 to 2048. | |||
Adjusted defult range envelopes in snf_engine.xml to be more conservative. | |||
20071017 - Version SNF2-9b1.5 | |||
Added a missing #include directive to the networking.hpp file. The | |||
missing #include was not a factor on Linux and Windows systems but | |||
caused compiler errors on BSD systems. | |||
Corrected a bug in the GBUdb White Range code where any message with a | |||
white range source IP was being forced to the white result code. The | |||
engine now (correctly) only forces the result and records the event when | |||
a black pattern rule was matched and the White Range IP causes that | |||
scan result to be overturned. If the scan result was not a black pattern | |||
match then the original scan result is allowed to pass through. | |||
Corrected a bug in the Header Analysis filter chain module that would | |||
cause the first header in the message to be ignored in some cases. | |||
Corrected an XML log format problem so that <s/> elements are correctly | |||
open ended <s ....> or closed (empty) <s..../> according to whether they | |||
have subordinate elements. | |||
Adjusted the GBUdb header info format. The order of the Confidence | |||
figure and Probabilty figure is now the same as in the XML log files | |||
(C then P). The confidence and probability figures are now preceeded | |||
with c= and p= respectively so that it's easy to tell which is which. | |||
20071009 Version 2-9b1.4 | |||
Tightened up the XCI handler code and removed the watchdog. The watchdog | |||
would restart the listener if there were no connections in 5 minutes. It | |||
was originally added to provide additional stability, however in practice | |||
there have been no "stalled listeners". Also, a stalled listener would | |||
likely be a sign of a different problem that the watchdog would tend to | |||
hide. | |||
Modified and refactored the XCI configuration management code. All XCI config | |||
changes and up-down operations are now handled in a single function except | |||
upon exit from the main XCI thread where XCI_shutdown() is always called. | |||
Added some more detailed exception handling code to the XCI component so that | |||
more data will be logged in the event of an error. | |||
Reviewed and modified the InstallInstructions.txt file. Removed this log | |||
to this separate file. | |||
Modified the snfmdplugin.xml file to properly configure the new features in | |||
the engine. | |||
* Header training directives and new <training/> section. | |||
* XCI interface configuration. | |||
* Tweaks to GBUdb ranges. | |||
* msg-file type configuration (not used in MDaemon, but configured anyway) | |||
---- | |||
Version 2-9a11 (engine a53) | |||
* Enhanced IP extraction from Received headers so that any unexpected bytes | |||
between the [ and ] will force the attempt to be aborted. | |||
* Fix the IP test code so that the IP 0.0.0.0 cannot be the source IP and | |||
cannot be tested. | |||
Version 2-9a11 (engine a52) | |||
* Corrected plug-in log entry logic. Allowed/Rejected tag now comes directly | |||
from the message rejection logic and is accurate in all cases. | |||
Version 2-9a10 (engine a52) | |||
* Corrected a bug in the MessageIPFunc where Ignore flagged IPs would still | |||
cause rejected messages if the statistics were in the Truncate range. Now | |||
messages are rejected in only two cases: | |||
The Flag is _Ugly_ and the rating is _Truncate_ or, the Flag is _Bad_. | |||
Version 2-9a9 (engine a52) | |||
* Adjusted IPtest module in HeaderAnalysis to handle TooManyIPs exception | |||
locally and silently. | |||
* Increased HeaderAnalysis IP limit from 20 to 50. | |||
Version 2-9a9 (engine a51) | |||
* Corrected possible heap corruption bug in EvaulationMatrix Destructors. | |||
* Added trace strings to scanMessage() for tighter panic reporting. | |||
* Added caching to snf_engine Evaluator allocation scheme. | |||
* Added optimizations to snf_engine Evaluator safety checks. | |||
Version 2-9a8 | |||
* Added deep exception handling to Token Matrix objects. | |||
Version 2-9a7 | |||
* Exception handling throughout the engine has been refactored to use std:exception | |||
and to provide additional detail via e.what() | |||
* The plug-in log will now show e.what() data as SNF Debug: whenever an exception | |||
is thrown during a message scan. | |||
Version 2-9a6 | |||
* Adjusted .ctl file path converter to accept either .msg or .tmp paths. | |||
Version 2-9a5 | |||
A lot of new things were learned, updated, and corrected. | |||
* Fixed the "lockup" when the plugin failed to start successfully. The cause of this | |||
appears to be a threading issue associated with DLLs that are being initialized. | |||
If threads are created during the initialization of a DLL, the DLL must succeed! | |||
The threads that are created do not get any cycles until after the DLL is loaded | |||
successfully. As a result, if the initialization process attempts to join() these | |||
threads a deadlock is created. The fix was to allow the SNF plugin initialization | |||
process to succeed in all cases while setting a flag that forces the engine to | |||
be inert if the initialization was not successful. When the DLL is later unloaded | |||
the threads are already running so the join() calls that are part of the engine | |||
cleanup code are able to complete without incident. | |||
* Installed detailed exception handling for the start-up sequence. The plugin can | |||
now report on very specific reasons for failing to initialize properly. | |||
* Fixed a bug in the GBUdbIgnoreList processor where long lines would cause the | |||
remainder of the file not to be read. The line length limit still exists, but | |||
it is now 255 characters which is unlikely to occur and would be considered | |||
incorrect formatting. | |||
* The threading library now includes top-level exception handling to trap any | |||
exception that was not handled by myTask(). Along with this two flags were | |||
added to thread objects: isRunning() and isBad(). isRunning() is true when a | |||
thread object is still active. isBad() is true if the thread failed to start or | |||
an exception escaped myTask(). | |||
* At least one GBUdbIgnoreList entry is now REQUIRED. If the count of IPs from the | |||
GBUdbIgnoreList.txt file is less than 1 (or the file is missing) then the plug-in | |||
will complain and fail to start. | |||
* snf2check.exe has been removed from the distribution for the time being since it | |||
causes some systems to strip the attachment or block the email. This is the same | |||
program that is already on existing SNF systems. |
@@ -0,0 +1,10 @@ | |||
# List of IPs to Ignore on startup | |||
# Each IP in this list is set to Ignore in GBUdb when | |||
# The configuration is loaded. | |||
# Hash mark on the beginning of a line indicates a comment. | |||
# Comments after an IP are also ignored. | |||
# One line per IP. Sorry, no CIDR yet. | |||
# Be sure to list ALL of your gateways :-) | |||
127.0.0.1 # ignore localhost, of course. | |||
@@ -0,0 +1,146 @@ | |||
MDaemon Plugin V2.9rc* (V3) installation instructions | |||
------------------------------------------------------------------------------ | |||
1. Locate your \MDaemon directory (Usually c:\MDaemon) | |||
2. Create the directory \MDaemon\SNF | |||
3. Copy the distribution files to \MDaemon\SNF | |||
4. Edit identity.xml in notepad. | |||
4.1. Replace licensid with your SNF license ID. | |||
4.2. Replace authenticationxx with your SNF authentication code. | |||
5. Adjust/Create your Plugins.dat file (\MDaemon\App\Plugins.dat) | |||
5.1. If you already have a Plugins.dat file | |||
5.1.1. Copy the contents of the Plugins.dat file in the distribution | |||
to the Plugins.dat file you have. | |||
5.1.2. If you have a [Message Sniffer] section in your Plugins.dat | |||
file then make a copy of it (for backup) then remove that | |||
section. (This will disable your previous Message Sniffer | |||
installation) | |||
5.2. If you do not already have a Plugins.dat file | |||
5.2.1. Copy the Plugins.dat file from the distribution to your | |||
\MDaemon\App directory. | |||
6. Copy the snf-groups.cf into \MDaemon\SpamAssassin\rules | |||
7. Download your SNF rulebase file and place it in your SNF directory. | |||
7.1. Once you've signed up for a 30 Day free Trial or purchased a license for | |||
SNF you will receive update notifications via email. These notifications | |||
contain instructions on how to download your rulebase file. You can get | |||
your 30 Day Free Trial started by visiting www.armresearch.com. | |||
7.2. We have included an update script and utilities that you can use to | |||
automate updates to your rulebase file. The SNFServer engine that runs | |||
inside the plugin will produce an UpdateReady.txt file any time the local | |||
rulbase file is older than the latest available update. The included | |||
getRulebase.cmd script checks for this file and uses the open source | |||
wget and gzip utilities to download, validate, and replace your rulebase | |||
file automatically. | |||
7.2.1. Edit the top of the getRulebase.cmd file to establish the correct | |||
working directory, authentication string, and license ID for your | |||
rulebase files. | |||
7.2.2. Verify that the <update-script/> section of your snfmdplugin.xml file | |||
points to the correct location of the getRulebase.cmd script. This new | |||
feature will automatically run the getRulebase.cmd script whenever a | |||
newer rulebase file is available on our servers. | |||
8. Edit the GBUdbIgnoreList.txt file in notepad. | |||
8.1 Add the IP of any gateways you have as well as any systems you | |||
have that send mail through your mail server. | |||
8.2 It is very important to populate your GBUdbIgnoreList if you have | |||
gateways ahead of your mail server or else GBUdb will learn that | |||
those systems are responsible for sending spam! The GBUdb engine | |||
uses the ignore list to determine the actual source IP of the message. | |||
The first IP it sees in the headers that is not on the ignore list | |||
is determined to be the source IP for the message. Since most email | |||
"in the wild" these days are spam, any gateways that are not listed | |||
will be seen to be sending mostly spam - in error, of course. | |||
8.3 You cannot enter network blocks in the GBUdbIgnoreList.txt file. If | |||
you wish to ignore (mark as infrastructure) blocks of IPs then you should | |||
use the <drilldown/> section of the snfmdplugin.xml file to enter | |||
patterns that match the network blocks you want to ignore. For example, | |||
if you want to ignore servers in the 12.34.56.0/24 network block then | |||
you would enter a drilldown rule like: | |||
<drilldown> | |||
... | |||
<received ordinal='0' find='[12.34.56.'/> | |||
The rule tells GBUdb to learn to ignore any IP in the top (ordinal 0) | |||
received header if that header contains the string '[12.34.56.'. Of | |||
course that string will match every IP in the 12.34.56.0/24 class C | |||
block so any servers in that block which deliver mail to the SNF equiped | |||
server will be learned as infrastructure (ignore flag set). | |||
9. Review and adjust your snfmdplugin.xml file | |||
9.1. Check the paths at the top of the file and make sure they are complete and | |||
correct. In most cases the defaults will work, but if you've installed | |||
MDaemon & SNF on a different drive or in a different directory it would | |||
be best to update these paths: | |||
9.1.1. Find/Check <snf><node identity.../> | |||
9.1.2. Find/Check <snf><node><paths><log path.../> | |||
9.1.3. Find/Check <snf><node><paths><rulebase path.../> | |||
9.1.4. Find/Check <snf><node><paths><workspace path.../> | |||
9.2. If you have any addresses where people legitimately send spam such as an | |||
abuse reporting address or support address then you should enter that | |||
address into the <snf><node><gbudb><training><bypass/> section of the | |||
snfmdplugin.xml file. For example an abuse reporting address might look | |||
like this: | |||
<bypass> | |||
... | |||
<header name='To:' find='spam@example.com'/> | |||
The rule tells GBUdb to bypass it's training mechanism if it finds a | |||
'To:' header in a message that contains 'spam@example.com'. This should | |||
prevent customer's IPs from being learned as spam sources when they send | |||
messages to spam@example.com. | |||
9.3. Your system practices and policies may require additional rules in order | |||
to get the best performance from the GBUdb system. For more information | |||
please check out www.armresearch.com, support@armresearch.com, and our | |||
community list sniffer@sortmonster.com. | |||
10. Restart MDaemon. | |||
11. Verify the SNF plugin is installed | |||
11.1. In the plug-ins log tab you should see: | |||
Attempting to load 'SNF' plugin | |||
* ConfigFunc: ConfigFunc@4 (Ok, ready to use) | |||
* StartupFunc: Startup@4 (Ok, ready to use) | |||
* ShutdownFunc: Shutdown@4 (Ok, ready to use) | |||
* PreMessageFunc: (NULL) | |||
* PostMessageFunc: MessageFunc@8 (Ok, ready to use) | |||
* SMTPMessageFunc: MessageIPFunc@8 (Ok, ready to use) | |||
* SMTPMessageFunc2: (NULL) | |||
* SMTPMessageFunc3: (NULL) | |||
* DomainPOPMessageFunc: (NULL) | |||
* MultiPOPMessageFunc: (NULL) | |||
* Result: success (plugin DLL loaded in slot 0) | |||
---------- | |||
SNF plugin is starting up | |||
SNFMulti Engine Version 2.9rc11 Build: Mar 20 2008 15:18:30 | |||
SNF MDaemon Plugin Version 2-9rc4 Build: Mar 20 2008 15:17:20 | |||
SNF Config: C:\MDaemon\SNF\SNFMDPlugin.xml | |||
---------- | |||
Note that the slot may be different if you have other plugins. | |||
11.2. When your system processes a message you should see something like: | |||
SNF MessageScan: c:\mdaemon\queues\local\md50000000039.msg, Result=0 | |||
If you have a valid AntiVirus for MDaemon license you should also see | |||
a line similar to this: | |||
SNF IPScan: C:\MDaemon\Queues\Inbound\md50000000029.msg, 192.168.0.102, {Ugly, p=-1, c=0.303425, Normal} Allowed. | |||
11.3. In your messages you should see some new headers similar to: | |||
X-MessageSniffer-GBUdb-Result: 0, 192.168.0.102, Ugly -1 0.303425 Source Normal | |||
X-MessageSniffer-Scan-Result: 0 | |||
X-MessageSniffer-Patterns: | |||
0-0-0-998-c |
@@ -0,0 +1,11 @@ | |||
[SNF] | |||
MenuText=Configure SNF Plug-in | |||
Enable=Yes | |||
DllPath=c:\MDaemon\SNF\snfmdplugin.dll | |||
StartupFuncName=Startup@4 | |||
ConfigFuncName=ConfigFunc@4 | |||
PostMessageFuncName=MessageFunc@8 | |||
SMTPMessageFuncName=MessageIPFunc@8 | |||
ShutdownFuncName=Shutdown@4 | |||
PluginDoesAllLogging=No | |||
NonAuthOnly=Yes |
@@ -0,0 +1,182 @@ | |||
SNFClient Readme | |||
Command line client for SNF. This utility formats and processes SNF_XCI | |||
requests through the SNF Engine working on the local machine. In general | |||
this utility can be used as a replacement for the earlier SNF command | |||
line scanner. It is also useful for other uses such as debugging and | |||
communicating with GBUdb. | |||
Note: Unlike prior versions of SNF, this command line utility does not | |||
need to be "branded" (renamed for the SNF license id). | |||
_________ | |||
Help Mode | |||
SNFClient.exe | |||
When called with no command line parameters the utility produces | |||
help and version information. | |||
__________ | |||
Debug Mode | |||
SNFDebugClient.exe | |||
When "debug" or "Debug" appears in the path to the program name | |||
or if the program's name is altered to include the word "debug" or | |||
"Debug" then the program will produce additional information about | |||
it's operation to aid in debugging problems. This includes the | |||
entire raw SNF_XCI request and response. | |||
__________________ | |||
Message Scan Modes | |||
These modes are used to scan email message files (the data part of | |||
smtp). This utility can be used as a drop-in replacement for previous | |||
verions of SNF (Message Sniffer) for scanning messages. However, this | |||
new version does not need to be "branded" (renamed for the license id) | |||
and will ignore the authentication string if it is provided. Also, | |||
since the newer version of SNF uses a client-server model and not a | |||
peer-server model, there is no need for a "persistent" mode. | |||
If "persistent" is passed to this utility on the command line as it | |||
would be used in prior versions of SNF then it will be treated like | |||
a file name and the scan will normally fail since a file named | |||
"persistent" is not likely to exist. | |||
SNFClient.exe <FileNameToScan> | |||
Scan Mode: Scans <FileNameToScan> and returns a result code. | |||
SNFClient.exe <authenticationxx> <FileNameToScan> | |||
Compatibility Mode: Ignores <authenticationxx> then scans the | |||
<FileNameToScan> and returns a result code. This mode provides | |||
drop-in compatibility with previous versions of SNF. | |||
SNFClient.exe -xhdr <FileNameToScan> | |||
XHeader Mode: Scans <FileNameToScan> and returns the result. Also | |||
outputs the contents of the X-Headers created by the SNF engine. If | |||
the SNF engine is configured to inject these headers then they will | |||
also have been injected into the <FileNameToScan>. | |||
The SNF Engine can be configured to provide the X-Headers only to | |||
the API without injecting them. In this case the XHeader Mode will | |||
display the X-Headers that would be injected, but they will not | |||
have been injected into the <FileNameToScan>. | |||
If the SNF Engine is configured not to produce X-Headers (none) then | |||
the XHeader Mode will not produce X-Headers because they will not | |||
have been generated by the engine. | |||
(note: -xhdr and -source options can be combined) | |||
SNFClient.exe -source=<IP4Address> <FileNameToScan> | |||
Source-IP Mode: Scans <FileNameToScan> and returns the result. The | |||
provided source IP is injected into the scan as the first Received | |||
header so that the scanning engine will presume the IP is the source | |||
of the message. This allows you to pre-define the source IP for the | |||
message when there is no other received header or when the received | |||
headers may be incorrect or may not present the actual source of | |||
the message. | |||
(note: -xhdr and -source options can be combined) | |||
_____________________________ | |||
SNFServer Status Report Modes | |||
SNFClient.exe -status.second | |||
SNFClient.exe -status.minute | |||
SNFClient.exe -status.hour | |||
This mode returns the latest posted status report as indicated. | |||
Normally these status reports are also posted to files in the | |||
SNFServer workspace. | |||
In this mode the SNFClient will return a result code (error level) | |||
of 0 when the request is successful and 99 (or some nonzero value) | |||
when the request is not successful. This allows the SNFClient to | |||
be used to verify that the SNFServer is running. | |||
Note: In most other modes the SNFClient returns a fail-safe 0 | |||
result code to avoid tagging messages as spam when there are errors. | |||
________________________ | |||
XCI Server Command Modes | |||
These features will expand as needed in later versions. | |||
SNFClient.exe -shutdown | |||
If the SNF Engine is running in an application that accepts SNF_XCI | |||
server commands then this mode will send that command. The shutdown | |||
command may have no effect if the application does not use the SNF_XCI | |||
server commnand interface or does not recognize the command. | |||
___________ | |||
GBUdb Modes | |||
These modes are used to communicate with the GBUdb system on the | |||
local node. It is possible to test (read out) an IP record or make | |||
any of a number of changes to IP data in the GBUdb. | |||
SNFClient.exe -test <IP4Address> | |||
Returns the current GBUdb statistics for the <IP4Address> | |||
SNFClient also returns a result code that matches the GBUdb range | |||
for the tested IP. These ranges are defined in the SNFServer | |||
configuration file. By default they are: | |||
20 - Truncate | |||
63 - Black | |||
40 - Caution | |||
0 - Normal | |||
SNFClient.exe -set <IP4Address> <flag> <bad> <good> | |||
Creates or updates the data for <IP4Address> as provided. The | |||
<IP4Address> must be provided as well as at least one of | |||
<flag>, <bad>, and <good>. If <flag>, <bad>, or <good> are | |||
to be left unchanged then they should be entered as a dash "-". | |||
Examples: | |||
Set all data for an IP. The flag will be "ugly", the bad count | |||
will be 0 and the good count will be 1000. | |||
SNFClient.exe -set 12.34.56.78 Ugly 0 1000 | |||
Set the flag to "ignore" and do not change the counts. | |||
SNFClient.exe -set 12.34.56.78 ignore - - | |||
Set the good count to 400 and do not change anything else. | |||
SNFClient.exe -set 12.34.56.78 - - 400 | |||
SNFClient.exe -good <IP4Address> | |||
Creates or updates statistics for the <IP4Address>. Increases the | |||
good count by one. (Record a good event) | |||
SNFClient.exe -bad <IP4Address> | |||
Creates or updates statistics for the <IP4Address>. Increases the | |||
bad count by one. (Record a bad event) | |||
SNFClient.exe -drop <IP4Address> | |||
Removes all local data for the <IP4Address>. Anything the local | |||
system "knows" about the IP is forgotten. Next time the IP is | |||
encountered it will be treated as new. | |||
____________________ | |||
For More Information | |||
See www.armresearch.com | |||
Copyright (C) 2007-2008 Arm Research Labs, LLC. | |||
@@ -0,0 +1,47 @@ | |||
@ECHO OFF | |||
SETLOCAL | |||
REM ----- Edit This Section -------- | |||
SET SNIFFER_PATH=\mdaemon\snf | |||
SET AUTHENTICATION=authenticationxx | |||
SET LICENSE_ID=licensid | |||
REM -------------------------------- | |||
CD /d %SNIFFER_PATH% | |||
if not exist UpdateReady.txt GOTO DONE | |||
if exist UpdateReady.lck GOTO DONE | |||
:DOWNLOAD | |||
COPY UpdateReady.txt UpdateReady.lck | |||
wget http://www.sortmonster.net/Sniffer/Updates/%LICENSE_ID%.snf -O %LICENSE_ID%.new.gz --header=Accept-Encoding:gzip --http-user=sniffer --http-passwd=ki11sp8m | |||
if exist %LICENSE_ID%.new.gz gzip -d -f %LICENSE_ID%.new.gz | |||
snf2check.exe %LICENSE_ID%.new %AUTHENTICATION% | |||
if errorlevel 1 goto CLEANUP | |||
if exist %LICENSE_ID%.old del %LICENSE_ID%.old | |||
rename %LICENSE_ID%.snf %LICENSE_ID%.old | |||
rename %LICENSE_ID%.new %LICENSE_ID%.snf | |||
if exist UpdateReady.txt del UpdateReady.txt | |||
if exist UpdateReady.lck del UpdateReady.lck | |||
:CLEANUP | |||
if exist %LICENSE_ID%.new del %LICENSE_ID%.new | |||
if exist UpdateReady.lck del UpdateReady.lck | |||
:DONE | |||
ENDLOCAL | |||
@@ -0,0 +1 @@ | |||
<snf><identity licenseid='licensid' authentication='authenticationxx'/></snf> |
@@ -0,0 +1,80 @@ | |||
## Basic rules for detecting Message Sniffer header emissions | |||
## so that they can be given scores in subsequent SpamAssassin | |||
## scanning. Modify the scores and headers as needed for your | |||
## system. | |||
score SNF_IPTRUNCATE 10 | |||
describe SNF_IPTRUNCATE IP Source consistently sends spam | |||
header SNF_IPTRUNCATE X-MessageSniffer-Scan-Result =~ /20/ | |||
score SNF_IPCAUTION 3 | |||
describe SNF_IPCAUTION New IP source mixed scan results | |||
header SNF_IPCAUTION X-MessageSniffer-Scan-Result =~ /40/ | |||
score SNF_IPBLACK 4 | |||
describe SNF_IPBLACK Static IP rules and GBUdb Black | |||
header SNF_IPBLACK X-MessageSniffer-Scan-Result =~ /63/ | |||
score SNF_OBFUSCATION 5 | |||
describe SNF_OBFUSCATION Obfuscation detection | |||
header SNF_OBFUSCATION X-MessageSniffer-Scan-Result =~ /62/ | |||
score SNF_ABSTRACT 5 | |||
describe SNF_ABSTRACT Abstracted spam patterns | |||
header SNF_ABSTRACT X-MessageSniffer-Scan-Result =~ /61/ | |||
score SNF_GENERAL 5 | |||
describe SNF_GENERAL General spam content - unclassified | |||
header SNF_GENERAL X-MessageSniffer-Scan-Result =~ /60/ | |||
score SNF_GAMBLE 5 | |||
describe SNF_GAMBLE Gambling and Casino spam patterns | |||
header SNF_GAMBLE X-MessageSniffer-Scan-Result =~ /59/ | |||
score SNF_DEBT 5 | |||
describe SNF_DEBT Debt and Credit offer spam patterns | |||
header SNF_DEBT X-MessageSniffer-Scan-Result =~ /58/ | |||
score SNF_GETRICH 5 | |||
describe SNF_GETRICH Home Biz, Stock Push, get rich quick | |||
header SNF_GETRICH X-MessageSniffer-Scan-Result =~ /57/ | |||
score SNF_TONER 5 | |||
describe SNF_TONER Ink and Toner offer spam patterns | |||
header SNF_TONER X-MessageSniffer-Scan-Result =~ /56/ | |||
score SNF_MALWARE 5 | |||
describe SNF_MALWARE Virus, worm, and exploit patterns | |||
header SNF_MALWARE X-MessageSniffer-Scan-Result =~ /55/ | |||
score SNF_ADULT 5 | |||
describe SNF_ADULT Porn and Adult spam patterns | |||
header SNF_ADULT X-MessageSniffer-Scan-Result =~ /54/ | |||
score SNF_SCAM 5 | |||
describe SNF_SCAM Phishing, 419, and other scam patterns | |||
header SNF_SCAM X-MessageSniffer-Scan-Result =~ /53/ | |||
score SNF_SNAKEOIL 5 | |||
describe SNF_SNAKEOIL Drugs, diet aids, health scams | |||
header SNF_SNAKEOIL X-MessageSniffer-Scan-Result =~ /52/ | |||
score SNF_SPAMWARE 5 | |||
describe SNF_SPAMWARE Spamming tools and spam hosting offers | |||
header SNF_SPAMWARE X-MessageSniffer-Scan-Result =~ /51/ | |||
score SNF_DATATHEFT 5 | |||
describe SNF_DATATHEFT Movies, software, unlimited downloads | |||
header SNF_DATATHEFT X-MessageSniffer-Scan-Result =~ /50/ | |||
score SNF_AVPUSH 5 | |||
describe SNF_AVPUSH Antivirus software push | |||
header SNF_AVPUSH X-MessageSniffer-Scan-Result =~ /49/ | |||
score SNF_INSURANCE 5 | |||
describe SNF_INSURANCE Insurance offer patterns | |||
header SNF_INSURANCE X-MessageSniffer-Scan-Result =~ /48/ | |||
score SNF_TRAVEL 5 | |||
describe SNF_TRAVEL Travel offer patterns | |||
header SNF_TRAVEL X-MessageSniffer-Scan-Result =~ /47/ |
@@ -0,0 +1,156 @@ | |||
<!-- SNFMulti V3.0 Configuration File, Setup: Typical of MDaemon Plugin --> | |||
<!-- http://www.armresearch.com/support/articles/software/snfServer/config/snfEngine.jsp --> | |||
<snf> | |||
<node identity='/MDaemon/SNF/identity.xml'> | |||
<paths> | |||
<log path='/MDaemon/SNF/'/> | |||
<rulebase path='/MDaemon/SNF/'/> | |||
<workspace path='/MDaemon/SNF/'/> | |||
</paths> | |||
<logs> | |||
<rotation localtime='no'/> | |||
<status> | |||
<second log='yes' append='no'/> | |||
<minute log='yes' append='no'/> | |||
<hour log='no' append='no'/> | |||
</status> | |||
<scan> | |||
<identifier force-message-id='no'/> | |||
<classic mode='none' rotate='no' matches='none'/> | |||
<xml mode='file' rotate='yes' matches='all' performance='yes' gbudb='yes'/> | |||
<xheaders> | |||
<output mode='inject'/> | |||
<version on-off='off'>X-MessageSniffer-Version</version> | |||
<license on-off='off'>X-MessageSniffer-License</license> | |||
<rulebase on-off='off'>X-MessageSniffer-RulebaseUTC</rulebase> | |||
<identifier on-off='off'>X-MessageSniffer-Identifier</identifier> | |||
<gbudb on-off='on'>X-MessageSniffer-GBUdb-Result</gbudb> | |||
<result on-off='on'>X-MessageSniffer-Scan-Result</result> | |||
<matches on-off='on'>X-MessageSniffer-Patterns</matches> | |||
<black on-off='off'>X-MessageSniffer-Spam: Yes</black> | |||
<white on-off='off'>X-MessageSniffer-White: Yes</white> | |||
<clean on-off='off'>X-MessageSniffer-Clean: Yes</clean> | |||
<symbol on-off='off' n='0'>X-MessageSniffer-SNF-Group: OK</symbol> | |||
<symbol on-off='off' n='20'>X-MessageSniffer-SNF-Group: Truncated</symbol> | |||
<symbol on-off='off' n='40'>X-MessageSniffer-SNF-Group: Caution</symbol> | |||
<symbol on-off='off' n='63'>X-MessageSniffer-SNF-Group: Black</symbol> | |||
<symbol on-off='off' n='62'>X-MessageSniffer-SNF-Group: Obfuscation</symbol> | |||
<symbol on-off='off' n='61'>X-MessageSniffer-SNF-Group: Abstract</symbol> | |||
<symbol on-off='off' n='60'>X-MessageSniffer-SNF-Group: General</symbol> | |||
<symbol on-off='off' n='59'>X-MessageSniffer-SNF-Group: Casinos-Gambling</symbol> | |||
<symbol on-off='off' n='58'>X-MessageSniffer-SNF-Group: Debt-Credit</symbol> | |||
<symbol on-off='off' n='57'>X-MessageSniffer-SNF-Group: Get-Rich</symbol> | |||
<symbol on-off='off' n='56'>X-MessageSniffer-SNF-Group: Ink-Toner</symbol> | |||
<symbol on-off='off' n='55'>X-MessageSniffer-SNF-Group: Malware</symbol> | |||
<symbol on-off='off' n='54'>X-MessageSniffer-SNF-Group: Porn-Dating-Adult</symbol> | |||
<symbol on-off='off' n='53'>X-MessageSniffer-SNF-Group: Scam-Phishing</symbol> | |||
<symbol on-off='off' n='52'>X-MessageSniffer-SNF-Group: Snake-Oil</symbol> | |||
<symbol on-off='off' n='51'>X-MessageSniffer-SNF-Group: Spamware</symbol> | |||
<symbol on-off='off' n='50'>X-MessageSniffer-SNF-Group: Media-Theft</symbol> | |||
<symbol on-off='off' n='49'>X-MessageSniffer-SNF-Group: AV-Push</symbol> | |||
<symbol on-off='off' n='48'>X-MessageSniffer-SNF-Group: Insurance</symbol> | |||
<symbol on-off='off' n='47'>X-MessageSniffer-SNF-Group: Travel</symbol> | |||
</xheaders> | |||
</scan> | |||
</logs> | |||
<network> | |||
<sync secs='30' host='sync.messagesniffer.net' port='25'/> | |||
<update-script on-off='on' call='/MDaemon/SNF/getRulebase.cmd' guard-time='180'/> | |||
</network> | |||
<xci on-off='on' port='9001'/> | |||
<gbudb> | |||
<database> | |||
<condense minimum-seconds-between='600'> | |||
<time-trigger on-off='on' seconds='86400'/> | |||
<posts-trigger on-off='off' posts='1200000'/> | |||
<records-trigger on-off='off' records='600000'/> | |||
<size-trigger on-off='on' megabytes='150'/> | |||
</condense> | |||
<checkpoint on-off='on' secs='3600'/> | |||
</database> | |||
<regions> | |||
<white on-off='on' symbol='0'> | |||
<edge probability='-1.0' confidence='0.4'/> | |||
<edge probability='-0.8' confidence='1.0'/> | |||
<panic on-off='on' rule-range='1000'/> | |||
</white> | |||
<caution on-off='on' symbol='40'> | |||
<edge probability='0.4' confidence='0.0'/> | |||
<edge probability='0.8' confidence='0.5'/> | |||
</caution> | |||
<black on-off='on' symbol='63'> | |||
<edge probability='0.8' confidence='0.2'/> | |||
<edge probability='0.8' confidence='1.0'/> | |||
<truncate on-off='on' probability='0.9' peek-one-in='5' symbol='20'/> | |||
<sample on-off='on' probability='0.8' grab-one-in='5' passthrough='no' passthrough-symbol='0'/> | |||
</black> | |||
</regions> | |||
<training on-off='on'> | |||
<bypass> | |||
<!-- <header name='To:' find='spam@example.com'/> --> | |||
<!-- <header name='Received:' ordinal='1' find='friendlyhost.com'/> --> | |||
</bypass> | |||
<drilldown> | |||
<!-- <received ordinal='0' find='[12.34.56.'/> where we want to ignore 12.34.56.0/24 --> | |||
<!-- <received ordinal='0' find='mixed-source.com'/> --> | |||
<!-- <received ordinal='1' find='mixed-source-internal.com'/> --> | |||
</drilldown> | |||
<source> | |||
<!-- <header name='X-Use-This-Source:' received='mixedsource.com [' ordinal='0' /> --> | |||
<!-- <header name='X-Originating-IP:' received='hotmail.com [' ordinal='0' /> --> | |||
</source> | |||
<white> | |||
<result code='1'/> | |||
<!-- <header name='Received:' ordinal='0' find='.friendlyhost.com'/> --> | |||
</white> | |||
</training> | |||
</gbudb> | |||
<rule-panics> | |||
<!-- | |||
<rule id='123456'/> | |||
<rule id='123457'/> | |||
--> | |||
</rule-panics> | |||
<!-- Platform Specific Configuration --> | |||
<platform> | |||
<mdaemon> | |||
<ip-test on-off='on'/> | |||
<configurator command='start notepad' append-path='yes'/> | |||
</mdaemon> | |||
</platform> | |||
<msg-file type='rfc822'/> | |||
</node> | |||
</snf> | |||
@@ -0,0 +1,6 @@ | |||
EXPORTS | |||
ConfigFunc@4 @1 | |||
MessageFunc@8 @2 | |||
MessageIPFunc@8 @3 | |||
Shutdown@4 @4 | |||
Startup@4 @5 |
@@ -0,0 +1,487 @@ | |||
// main.cpp | |||
// SNF MDaemon Plugin | |||
// Copyright (C) 2007-2008, ARM Research Labs, LLC. | |||
#include <windows.h> | |||
#include "mdconfiguration.hpp" | |||
#include "../SNF_Service/SNFMulti.hpp" | |||
#define DLL_EXPORT __declspec(dllexport) | |||
//////////////////////////////////////////////////////////////////////////////// | |||
// Constants And Tweaks | |||
//////////////////////////////////////////////////////////////////////////////// | |||
const int MDPLUGIN_MSG = 22000; | |||
const int MDPLUGIN_DISPLAY = 22001; | |||
const char* PLUGIN_VERSION_INFO = "SNF MDaemon Plugin Version 3.0 Build: " __DATE__ " " __TIME__; | |||
//////////////////////////////////////////////////////////////////////////////// | |||
// SNF MDaemon Plugin DLL Interface Setup. | |||
//////////////////////////////////////////////////////////////////////////////// | |||
extern "C" { // All of these "C" functions for export. | |||
BOOL WINAPI DllMain ( HINSTANCE hInst, DWORD wDataSeg, LPVOID lpvReserved ); // The DllMain starup/shutdown function. | |||
DLL_EXPORT void _stdcall Startup(HWND Parent); // Startup Function. | |||
DLL_EXPORT void _stdcall ConfigFunc(HWND Parent); // Configuration function. | |||
DLL_EXPORT void _stdcall MessageFunc(HWND Parent, const char* File); // Message Scan Function. | |||
DLL_EXPORT void _stdcall MessageIPFunc(HWND Parent, const char* File); // IP Scan Function. | |||
DLL_EXPORT void _stdcall Shutdown(HWND Parent); // Shutdown Function. | |||
} | |||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { // Thread attach/detach functions. | |||
switch (fdwReason) { // Switch on the reason for the call. | |||
case DLL_PROCESS_ATTACH: // Attach to process. | |||
/*** Startup function moved to API ***/ | |||
return true; // We will assume it worked. | |||
break; | |||
case DLL_PROCESS_DETACH: // Detach from process. | |||
/*** Shutdown function moved to API ***/ | |||
return true; // We will assume that worked. | |||
break; | |||
case DLL_THREAD_ATTACH: // Attach to thread | |||
break; // Just be happy. | |||
case DLL_THREAD_DETACH: // Detach from thread | |||
break; // Just be happy. | |||
} | |||
return true; // Be happy by default. | |||
} | |||
//////////////////////////////////////////////////////////////////////////////// | |||
// SNF MDaemon Plugin Engine Code | |||
//////////////////////////////////////////////////////////////////////////////// | |||
// Handy Debug Functions. This is how we can display critical events on screen | |||
// and emit entries into the MDaemon logs. | |||
HWND LatestParent = 0; // Handle MDaemon log operations. | |||
void sayToScreen(const string StuffToSay) { // Display a modal system message. | |||
MessageBox ( // Use a message box. | |||
GetFocus(), // Take the user's focus. | |||
StuffToSay.c_str(), // This is what to say. | |||
"Message Sniffer Plug-In", // This is how to title the box. | |||
MB_OK|MB_SYSTEMMODAL ); // This makes it modal with a button. | |||
} | |||
void sayToLog(const string Msg) { // Emit message into MDaemon log. | |||
if(0 != LatestParent) { // If we have a handle: | |||
COPYDATASTRUCT Packet; // Create a packet for the log. | |||
Packet.dwData = MDPLUGIN_DISPLAY; | |||
Packet.cbData = Msg.length(); | |||
Packet.lpData = reinterpret_cast<void*>( | |||
const_cast<char*>(Msg.c_str())); | |||
SendMessage(LatestParent, MDPLUGIN_MSG, MDPLUGIN_DISPLAY, // Send the packet. | |||
(LPARAM)(PCOPYDATASTRUCT)&Packet); | |||
} | |||
} | |||
// The configuration file path is theoretically in a fixed location based on | |||
// the installation directory of MDaemon. We read the installation directory | |||
// from the registry and derive the path from that. If we get what we want | |||
// then we return the full path to the SNFMDPlugin.xml file - which is derived | |||
// from snf_engine.xml. If we don't get what we want then we return nothing. | |||
string ConfigurationFilePath() { // Get the config file path. | |||
char data[256]; // Create a buffer. | |||
DWORD dwType = 0; // Type holder. | |||
DWORD dwCount = sizeof(data); // Data counter. | |||
HKEY rkey; // Key handle. | |||
string KeyLocation("SOFTWARE\\Alt-N Technologies\\MDaemon"); // Key location. | |||
string KeyValueName("AppPath"); // Value name. | |||
// Open the key and if successful read it's value. | |||
string ReadValue = ""; // We'll put the answer here. | |||
if(ERROR_SUCCESS == // Try to open the registry | |||
RegOpenKeyEx(HKEY_LOCAL_MACHINE, KeyLocation.c_str(), 0, KEY_READ, &rkey) | |||
) { // If it opened successfully: | |||
RegQueryValueEx( // Read the MDaemon AppPath key. | |||
rkey, | |||
KeyValueName.c_str(), | |||
NULL, | |||
&dwType, | |||
(LPBYTE)&data, | |||
&dwCount | |||
); | |||
ReadValue = data; // Convert the results to a string. | |||
RegCloseKey(rkey); // Close the registry key. | |||
// Now we must convert the APP path to our SNFMDPlugin path. | |||
int PathEnd = ReadValue.length(); // Grab the length. | |||
if(PathEnd > 0) { ReadValue.erase(PathEnd-1,1); } // Eat the stroke at the end. | |||
PathEnd = ReadValue.find_last_of("\\"); // Find the next stroke in. | |||
int PathLength = ReadValue.length(); // Grab the path length. | |||
int EraseSpan = PathLength - (PathEnd+1); // Calculate the amount to erase. | |||
ReadValue.erase(PathEnd+1,EraseSpan); // Erase it to get the root path. | |||
ReadValue.append("SNF\\SNFMDPlugin.xml"); | |||
} | |||
// Return either the empty string or the configuration file path. | |||
return ReadValue; // Return what we have. | |||
} | |||
// Here are out engine components, startup, and shutdown logic. The actual | |||
// engine components are built as the DLL is loaded. They are "lit up" by the | |||
// startup() function - which is called when an application attaches to this | |||
// DLL; and they are closed down when an application detaches from this DLL. | |||
// 20080311 _M Added configuration interpreter for <platform/> and linked it | |||
// to the ConfigFunc() and MessageIPFunc() functions. | |||
volatile bool EngineIsGood = false; // True when things are ready to go. | |||
snf_RulebaseHandler* Rulebase = 0; // Our Rulebase Handler. | |||
snf_EngineHandler* ScanEngine = 0; // Our Scan Engine. | |||
int Generation = -1; // Configuration generation tag. | |||
string Configuration; // Configuration file path. | |||
MDConfiguration* PlatformConfig = 0; // Platform config interpreter. | |||
DLL_EXPORT void _stdcall Startup(HWND Parent) { // How to get all this started. | |||
LatestParent = Parent; | |||
EngineIsGood = false; // Start off pessimistically. | |||
try { // Be sure to catch any exceptions. | |||
Rulebase = new snf_RulebaseHandler(); // Create our rulebase handler. | |||
ScanEngine = new snf_EngineHandler(); // Create our engine scanner. | |||
Configuration = ConfigurationFilePath(); // Get the configuration path. | |||
PlatformConfig = new MDConfiguration(*Rulebase, Configuration); // Set up our configuration monitor. | |||
Rulebase->open(Configuration.c_str(), "", ""); // Open a configured rulebase. | |||
Rulebase->PlatformVersion(PLUGIN_VERSION_INFO); // Set the Platform version string. | |||
ScanEngine->open(Rulebase); // Open the scanning engine. | |||
EngineIsGood = true; // If all went well, we're up! | |||
sayToLog(Rulebase->EngineVersion()); // version info to show we're ok. | |||
sayToLog(Rulebase->PlatformVersion()); // Log our platform and engine | |||
string ConfigInfo = "SNF Config: "; // Build a configuration info | |||
ConfigInfo.append(Configuration); // message and display that | |||
sayToLog(ConfigInfo); // too. | |||
} | |||
catch(snf_RulebaseHandler::ConfigurationError) { // Can't work with config file! | |||
string ErrorMessage = "Unable to Configure with: "; // Tell them about it and give | |||
ErrorMessage.append(Configuration); // them a hint where we looked. | |||
sayToScreen(ErrorMessage); | |||
} | |||
catch(snf_RulebaseHandler::FileError) { // Can't load the rulebase file! | |||
string ErrorMessage = "Unable to Load Rulebase in: "; // Tell them about it and give | |||
ErrorMessage.append(Configuration); // them a hint where we looked. | |||
sayToScreen(ErrorMessage); | |||
} | |||
catch(snf_RulebaseHandler::AllocationError) { // Can't allocate memory! | |||
sayToScreen("Unable to Allocate Enough Memory!"); // Tell them about it. | |||
} | |||
catch(snf_RulebaseHandler::IgnoreListError) { // Can't load ignore list! | |||
sayToScreen("Unable to Load Ingore List!"); // Tell them about it. | |||
} | |||
catch(snf_RulebaseHandler::AuthenticationError) { // Can't authenticate! | |||
sayToScreen("Unable to Authenticate Rulebase!"); // Tell them about it. | |||
} | |||
catch(snf_RulebaseHandler::Busy) { // Busy?!! That's weird. | |||
sayToScreen("Busy Exception?!!"); // Tell them about it. | |||
} | |||
catch(snf_RulebaseHandler::Panic) { // Panic?!! That's weird. | |||
sayToScreen("Panic Exception?!!"); // Tell them about it. | |||
} | |||
catch(exception& e) { // Some other runtime error? | |||
sayToScreen(e.what()); // Tell them what it was. | |||
} | |||
catch(...) { // Catch the unknown exception. | |||
sayToScreen("Unexpected Exception!"); // Tell them things didn't work. | |||
} | |||
return; // All done. | |||
} | |||
/****** THE FOLLOWING IS DEFUNCT, BUT USEFUL INFO SO WE KEEP IT! ******/ | |||
/**** *Note: Why do we always return true even when we fail??? | |||
***** Because, in a DLL that is being loaded, none of the threads that | |||
***** get created in the rulebase object will get any cycles until the | |||
***** DLL load sequence is complete _AND_SUCCESSFUL_! | |||
***** | |||
***** The same is true when we return false -- because then the OS KNOWS | |||
***** that it's not safe to run any of the threads we've created. | |||
***** | |||
***** As a result, if we try to destroy our rulebase manager after an | |||
***** unsuccessful load then all of the stop() calls to our threads will | |||
***** block waiting for the initialized threads to see their stop bits and | |||
***** end. Since none of these threads actually get any love until the | |||
***** DLL is successfully loaded, we end up waiting happily for ever! | |||
***** | |||
***** Instead of stepping into this world of hurt, we've decided to leave | |||
***** the internal flag set to indicate that the engine is Not-Good so that | |||
***** the scanning functions remain inert, and then we wait patiently for | |||
***** the DLL to be unloaded. | |||
***** | |||
***** When that happens, since the OS KNOWS the DLL was loaded happily | |||
***** before, the objects can go through their normal destruction without | |||
***** deadlocking on their stop() functions (join()). | |||
****/ | |||
DLL_EXPORT void _stdcall Shutdown(HWND Parent) { // How to get all this stopped. | |||
LatestParent = Parent; | |||
if(EngineIsGood) { // If the engine is good: | |||
try { | |||
EngineIsGood = false; // Stop using the engine now. | |||
LatestParent = 0; // No more logging calls. | |||
if(ScanEngine) { // Close the scanner if it exists: | |||
ScanEngine->close(); // Close it. | |||
delete ScanEngine; // Delete it. | |||
ScanEngine = 0; // Forget it. | |||
} | |||
if(Rulebase) { // Close the rulebase if it exists. | |||
Rulebase->close(); // Close it. | |||
delete Rulebase; // Delete it. | |||
Rulebase = 0; // Forget it. | |||
} | |||
if(PlatformConfig) { // Drop the PlatformConfig if it be. | |||
delete PlatformConfig; // Delete it. | |||
PlatformConfig = 0; // Forget it. | |||
} | |||
Generation = -1; // Reset our config gen tag. | |||
sayToLog("SNF: Plugin Shutdown."); // Tell them we're shut down. | |||
} | |||
catch(exception& e) { // If we have a runtime exception | |||
string InShutdown = "SNF, Shutdown: "; // make a human friendly message | |||
InShutdown.append(e.what()); // and package the exception for | |||
sayToScreen(InShutdown); // a screen pop-up. | |||
} | |||
catch(...) { // If we see some other kind of | |||
sayToScreen("SNF, Shutdown: Unknown Exception"); // exception then show that. | |||
} | |||
} | |||
return; // All done. | |||
} | |||
// Now we get to the business end of the plugin. Three functions are exported. | |||
// ConfigFunc() launches an editor for the configuration file. | |||
// 20080311 _M Adjusted ConfigFunc to use Platform Configuration Parameters. | |||
DLL_EXPORT void _stdcall ConfigFunc(HWND Parent) { // Configuration function. | |||
LatestParent = Parent; // Capture the parent for logging. | |||
string ConfiguratorString = PlatformConfig->ConfiguratorCommand(); // Get Configurator launch command. | |||
if(0 < ConfiguratorString.length()) system(ConfiguratorString.c_str()); // If we have a launch command use it. | |||
} | |||
// MessageFunc() scans a message file and injects headers. | |||
DLL_EXPORT void _stdcall MessageFunc(HWND Parent, const char* File) { // Message Scan Function. | |||
LatestParent = Parent; // Capture the parent for logging. | |||
string LogMessage = "SNF MessageScan: "; // Start a plugin log entry. | |||
LogMessage.append(File); // add the file name. | |||
if(false == EngineIsGood) { // If the engine is not up then | |||
LogMessage.append(", Engine Not Ready!"); // report that in the plug-in log. | |||
sayToLog(LogMessage); // Post our entry to the plug-in log. | |||
return; // We're done. | |||
} | |||
// We are ready to begin our scan. | |||
int ResultCode = 0; // Keep track of the scan result. | |||
try { // Be sure to catch any exceptions. | |||
ResultCode = ScanEngine->scanMessageFile(File); | |||
} | |||
catch(snf_EngineHandler::FileError& e) { // Exception when a file won't open. | |||
LogMessage.append(", File Error!"); | |||
sayToLog(LogMessage); | |||
string DebugData = "SNF Debug: "; | |||
DebugData.append(e.what()); | |||
sayToLog(DebugData); | |||
return; | |||
} | |||
catch(snf_EngineHandler::XHDRError& e) { // Exception when XHDR Inject/File fails. | |||
LogMessage.append(", X-Header Error!"); | |||
sayToLog(LogMessage); | |||
string DebugData = "SNF Debug: "; | |||
DebugData.append(e.what()); | |||
sayToLog(DebugData); | |||
return; | |||
} | |||
catch(snf_EngineHandler::BadMatrix& e) { // Exception out of bounds of matrix. | |||
LogMessage.append(", Bad Matrix!"); | |||
sayToLog(LogMessage); | |||
string DebugData = "SNF Debug: "; | |||
DebugData.append(e.what()); | |||
sayToLog(DebugData); | |||
return; | |||
} | |||
catch(snf_EngineHandler::MaxEvals& e) { // Exception too many evaluators. | |||
LogMessage.append(", Too Many Evaluators!"); | |||
sayToLog(LogMessage); | |||
string DebugData = "SNF Debug: "; | |||
DebugData.append(e.what()); | |||
sayToLog(DebugData); | |||
return; | |||
} | |||
catch(snf_EngineHandler::AllocationError& e) { // Exception when we can't allocate something. | |||
LogMessage.append(", Allocation Error!"); | |||
sayToLog(LogMessage); | |||
string DebugData = "SNF Debug: "; | |||
DebugData.append(e.what()); | |||
sayToLog(DebugData); | |||
return; | |||
} | |||
catch(snf_EngineHandler::Busy& e) { // Exception when there is a collision. | |||
LogMessage.append(", Engine Busy!"); | |||
sayToLog(LogMessage); | |||
string DebugData = "SNF Debug: "; | |||
DebugData.append(e.what()); | |||
sayToLog(DebugData); | |||
return; | |||
} | |||
catch(snf_EngineHandler::Panic& e) { // Exception when something else happens. | |||
LogMessage.append(", Engine Panic!"); | |||
sayToLog(LogMessage); | |||
string DebugData = "SNF Debug: "; | |||
DebugData.append(e.what()); | |||
sayToLog(DebugData); | |||
return; | |||
} | |||
catch(exception& e) { // Some unexpected exception. | |||
LogMessage.append(", Unexpected Exception!"); | |||
sayToLog(LogMessage); | |||
string DebugData = "SNF Debug: "; | |||
DebugData.append(e.what()); | |||
sayToLog(DebugData); | |||
return; | |||
} | |||
catch(...) { // We should never get one of these, but | |||
LogMessage.append(", Non-Std Exception!"); // if we do we have something to say. | |||
sayToLog(LogMessage); | |||
return; | |||
} | |||
// At this point we know our scan worked ok. So, let's post the result. | |||
ostringstream O; // A stringstream makes it easy to | |||
O << LogMessage << ", Result=" << ResultCode; // format our plug-in log entry. | |||
sayToLog(O.str()); // Then we post it to the plug-in log. | |||
} | |||
// ControlFilePath(MessageFilePath) Converts .msg path to .ctl path. | |||
string ControlFilePath(string MessageFilePath) { // Convert .msg/.tmp to .ctl path. | |||
const string ControlFileExt(".ctl"); // Control file extension. | |||
const string EmptyString(""); // The empty string. | |||
string ControlFilePath(MessageFilePath); // Start with the message path. | |||
string::size_type CFExtPosition = ControlFilePath.find_last_of('.'); // Find the extension. | |||
if(string::npos == CFExtPosition) return EmptyString; // If we didn't find it return "" | |||
ControlFilePath.replace( // Replace the message file | |||
CFExtPosition, ControlFileExt.length(), // extension with the control | |||
ControlFileExt // file extension. | |||
); | |||
return ControlFilePath; | |||
} | |||
// MessageIPFunc() looks at the control file for a message, extracts the | |||
// source IP, and deletes the message if the IP is in the truncate range. | |||
DLL_EXPORT void _stdcall MessageIPFunc(HWND Parent, const char* File) { // IP Scan Function. | |||
LatestParent = Parent; // Capture the parent for logging. | |||
if(false == PlatformConfig->MessageIPFuncOn()) { // If the IP func is off: | |||
return; // We're done. | |||
} | |||
string LogMessage = "SNF IPScan: "; // Start a plugin log entry. | |||
LogMessage.append(File); // add the file name. | |||
if(false == EngineIsGood) { // If the engine is not up then | |||
LogMessage.append(", Engine Not Ready!"); // report that in the plug-in log. | |||
sayToLog(LogMessage); // Post our entry to the plug-in log. | |||
return; // We're done. | |||
} | |||
// Open the control file and find the RemoteIP | |||
const string CtlRemoteIP("RemoteIP="); // This is what we're looking for. | |||
string RemoteIP = ""; // This is where it will go. | |||
try { // Do this safely. | |||
ifstream ControlFile(ControlFilePath(File).c_str()); // Open the control file. | |||
while(ControlFile) { // While the file is good... | |||
string Line; // Read one line at a time | |||
getline(ControlFile, Line); // into a string. | |||
string::size_type TagPos = Line.find(CtlRemoteIP); // Look for the RemoteIP tag. | |||
if(string::npos != TagPos) { // If we find the RemoteIP tag: | |||
RemoteIP = Line.substr(TagPos + CtlRemoteIP.length()); // Get the string after the tag | |||
break; // We're done with the ctl file! | |||
} | |||
} | |||
ControlFile.close(); // Be nice and close our file. | |||
} | |||
catch(...) {} // Eat any exceptions. | |||
if(0 == RemoteIP.length()) { // If we didn't get the IP then | |||
LogMessage.append(", Didn't Get Remote IP!"); // make that the rest of our log | |||
sayToLog(LogMessage); // entry and post it. | |||
return; // We're done. | |||
} | |||
// At this point we have the remote IP to check. | |||
LogMessage.append(", "); LogMessage.append(RemoteIP); // Add the IP to the log entry. | |||
IPTestRecord IPAnalysis(RemoteIP); // Set up a test record. | |||
try { // Safely, | |||
Rulebase->performIPTest(IPAnalysis); // check the IP w/ GBUdb. | |||
} | |||
catch(...) { // If we encountered a problem | |||
LogMessage.append(", Analysis Failed!"); // then we need to report that | |||
sayToLog(LogMessage); // our analysis failed. | |||
return; // We're done. | |||
} | |||
// At this point we've got a good analysis, so we take action (if needed) | |||
// and produce a helpful log entry. | |||
ostringstream Happy; // A stringstream for easy formatting. | |||
Happy << LogMessage << ", {"; // Start the analysis report. | |||
switch(IPAnalysis.G.Flag()) { // Identify the flag data for this IP. | |||
case Good: Happy << "Good, "; break; | |||
case Bad: Happy << "Bad, "; break; | |||
case Ugly: Happy << "Ugly, "; break; | |||
case Ignore: Happy << "Ignore, "; break; | |||
} | |||
Happy << "p=" << IPAnalysis.G.Probability() << ", " // Probability and Confidence. | |||
<< "c=" << IPAnalysis.G.Confidence() << ", "; | |||
switch(IPAnalysis.R) { // The Range analysis. | |||
case Unknown: { Happy << " Unknown}"; break; } // Unknown - not defined. | |||
case White: { Happy << " White}"; break; } // This is a good guy. | |||
case Normal: { Happy << " Normal}"; break; } // Benefit of the doubt. | |||
case New: { Happy << " New}"; break; } // It is new to us. | |||
case Caution: { Happy << " Caution}"; break; } // This is suspicious. | |||
case Black: { Happy << " Black}"; break; } // This is bad. | |||
case Truncate: { Happy << " Truncate}"; break; } // This is bad unless we ignore it. | |||
} | |||
string WhatWeDid; // So, what do we do? | |||
if( // Are we in Truncate land? | |||
(Truncate == IPAnalysis.R && Ugly == IPAnalysis.G.Flag()) || // If the IP is Truncate & Ugly, or | |||
Bad == IPAnalysis.G.Flag() // If the IP is just plain bad then | |||
) { // we are in truncate land so we | |||
Happy << " Rejected!"; WhatWeDid = "Rejected"; // mark the message Rejected! and | |||
remove(File); // remove the file to reject it! | |||
} else { // If we are not rejecting the | |||
Happy << " Allowed."; WhatWeDid = "Allowed"; // message tell them it's allowed. | |||
} | |||
Rulebase->logThisIPTest(IPAnalysis, WhatWeDid); // Log the event. | |||
sayToLog(Happy.str()); // Post to the plug-in log. | |||
} |
@@ -0,0 +1,68 @@ | |||
// mdconfiguration.cpp | |||
// SNF MDaemon Plugin: Platform Configuration Module | |||
// Copyright (C) 2007-2008, ARM Research Labs, LLC. | |||
#include "mdconfiguration.hpp" | |||
MDConfiguration::MDConfiguration(snf_RulebaseHandler& R, string& C) : // Default constructor. | |||
MyCFGReader("mdaemon"), // The top element is "mdaemon" | |||
MyGeneration(-1), // Our first real gen will be 0. | |||
MyMessageIPFuncOn(true), // By default the IP func is on. | |||
MyConfiguratorCommand("start notepad"), // By default we start notepad to | |||
MyAppendConfigurationFileOn(true), // edit our config and pass it the path. | |||
MyConfigurationPath(C), // This is the config file path. | |||
MyRulebase(R) { // This is the rulebase manager. | |||
// Here we construct the configuration elements that will parse the platform | |||
// configuration data from our rulebase manager. | |||
MyCFGReader | |||
.Element("ip-test") | |||
.Attribute("on-off", MyMessageIPFuncOn, false) | |||
.End("ip-test") | |||
.Element("configurator") | |||
.Attribute("command", MyConfiguratorCommand, "") | |||
.Attribute("append-path", MyAppendConfigurationFileOn, true) | |||
.End("configurator") | |||
.End("mdaemon"); | |||
} | |||
int MDConfiguration::Generation() { // When checking our generation we | |||
return MyGeneration; // need only return what we have. | |||
} | |||
bool MDConfiguration::MessageIPFuncOn() { // Are we using the MessageIP function? | |||
ScopeMutex EverybodyFreeze(MyMutex); // Freeze the mutex. | |||
updateConfig(); // Update the configuration if needed. | |||
return MyMessageIPFuncOn; // Return the IP Func On/Off value. | |||
} | |||
string MDConfiguration::ConfiguratorCommand() { // Return proper configurator command. | |||
ScopeMutex EverybodyFreeze(MyMutex); // Freeze the mutex. | |||
updateConfig(); // Update the configuration. | |||
string ConfiguratorCommandString = ""; // Keep this in scope. | |||
if(0 < MyConfiguratorCommand.length()) { // If we have a command configured: | |||
ConfiguratorCommandString = MyConfiguratorCommand; // capture that command. | |||
if(MyAppendConfigurationFileOn) { // If we are supposed to append the | |||
ConfiguratorCommandString.append(" "); // configuration file path then | |||
ConfiguratorCommandString.append(MyConfigurationPath); // tack that on the end. | |||
} // If the configure command string was | |||
} // configured empty we will return "". | |||
return ConfiguratorCommandString; // Send back what we got. | |||
} | |||
void MDConfiguration::updateConfig() { // Parse & update the config if needed. | |||
if(MyGeneration != MyRulebase.Generation()) { // If our config is out of sync: | |||
try { // Catch any parsing errors. | |||
string NewConfiguration = MyRulebase.PlatformConfiguration(); // Grab the configuration string. | |||
ConfigurationData MyConfigData( // Load the configuration string | |||
NewConfiguration.c_str(), NewConfiguration.length()); // into a configuration data object. | |||
MyCFGReader.initialize(); // Initialize the parser and | |||
MyCFGReader.interpret(MyConfigData); // feed it the object. | |||
MyGeneration = MyRulebase.Generation(); // Grab the new generation tag. | |||
} | |||
catch(...) { } // Eat any thrown exceptions. | |||
} // If we're in sync we don't budge. | |||
} | |||
@@ -0,0 +1,47 @@ | |||
// mdconfiguration.hpp | |||
// SNF MDaemon Plugin: Platform Configuration Module | |||
// Copyright (C) 2007-2008, ARM Research Labs, LLC. | |||
// This module handles the platform specific configuration for the MDaemon | |||
// plugin. The rulebase is passed to the object when constructed. Each call to | |||
// get a parameter from the object causes a quick check to the generation data. | |||
// If the generation is still valid then the data is provided as is. If not then | |||
// the configuration is updated before it is returned. All of this is protected | |||
// by a mutex. | |||
#ifndef included_mdconfiguration_hpp | |||
#define included_mdconfiguration_hpp | |||
#include <windows.h> | |||
#include "../SNF_Service/SNFMulti.hpp" | |||
#include "../SNF_Service/configuration.hpp" | |||
#include "../SNF_Service/threading.hpp" | |||
class MDConfiguration { | |||
private: | |||
Mutex MyMutex; // Protects configuration. | |||
ConfigurationElement MyCFGReader; // This is how we read our cfg data. | |||
string& MyConfigurationPath; // Configuration file path. | |||
snf_RulebaseHandler& MyRulebase; // Rulebase manager at startup. | |||
volatile int MyGeneration; // Numeric Generation Tag. | |||
bool MyMessageIPFuncOn; // Message IP test on/off switch. | |||
string MyConfiguratorCommand; // Config editor command string. | |||
bool MyAppendConfigurationFileOn; // Append config file path to command? | |||
void updateConfig(); // Update config if needed. | |||
public: | |||
MDConfiguration(snf_RulebaseHandler& R, string& C); // Default constructor. | |||
int Generation(); // Numeric generation tag. | |||
bool MessageIPFuncOn(); // Message IP test on/off switch. | |||
string ConfiguratorCommand(); // Configure function command string. | |||
}; | |||
#endif | |||