In this section
•General Information
•Script for Milter
•Script for Spamd
•Script for Rspamd
•Script for SMTP
•Tables Describing the Message Structure
•Available Auxiliary Modules
General Information
The Dr.Web MailD component supports interaction via the Lua program interpreter (version 5.3.4 is used; it is supplied together with Dr.Web for UNIX Mail Servers). Scripts written in Lua can be used by the component for the analyzing and processing of email messages.
Email messages received via Milter, Spamd, Rspamd, or in the SMTP mode are analyzed with the help of a Lua script specified in the settings of Dr.Web MailD as the value of the MilterHook, SpamdHook, RspamdHook or Smtphook parameter respectively. You can specify the value of these parameters either as the full text of the script or as the path to it.
Script for Message Processing for the Milter Interface
Requirements for the Script
The script must contain a global function, that is an entry point in the message scanning module (Dr.Web MailD will call this function for processing all incoming messages). The processing function should match the following call conventions:
1.Function name is milter_hook;
2.The only argument is the MilterContext table (provides access from the function to the information about the processed email message);
3.The only returned value is the MilterResult completed table. The returned value defines a verdict about the scanned message: accept, reject, change, or discard, as well as actions to be applied (possibly) to the message if it is accepted.
Below you can see an example of a correctly defined function that always returns to Dr.Web MailD the accept verdict for all messages received for scanning via the Milter interface (here and after the ctx argument is an instance of the MilterContext table):
function milter_hook(ctx)
return {action = "accept"}
end
|
Examples
1.Detecting threats and checking for signs of spam
The script below performs the following operations:
•adds names of threats detected in an email message as values of the header X-Found;
•adds the [SPAM] prefix to the email subject (the value of the header Subject) if the spam score exceeds 100 points;
•sends the message to the recipient after it is processed.
function milter_hook (ctx)
-- Add the detected threats’ names to the header
for threat in ctx.message.threats() do
ctx.modifier.add_header_field("X-Found", threat.name)
end
-- Change the value of the Subject header, if a message has more than 100 points of spam scoring
if ctx.message.spam.score > 100 then
local old_value = ctx.message.header.value("Subject") or ""
local new_value = "[SPAM] " .. old_value
ctx.modifier.change_header_field("Subject", new_value)
end
-- Send a message to a recipient, applying the pending changes
return {
action = "accept",
modifications = ctx.modifier.modifications()
}
end
|
2.Placing all detected threats in a protected archive and archiving the message (if the spam score is exceeded)
The script below performs the following operations:
•places the detected threats in a protected archive;
•places an email message in a protected archive if the spam score exceeds 100 points.
function milter_hook(ctx)
ctx.modifier.repack_password = "xxx"
ctx.modifier.repack_message = ""
-- Move all message parts where threats were found
-- to a password protected archive
for threat, path in ctx.message.threats() do
ctx.modifier.repack(path)
local msg = " Threat found: " .. threat.name
ctx.modifier.repack_message = ctx.modifier.repack_message .. msg
end
-- Repack the whole email message if it has
-- more than 100 points of spam scoring
if ctx.message.spam.score > 100 then
ctx.modifier.repack()
local msg = " Spam score: " .. ctx.message.spam.score
ctx.modifier.repack_message = ctx.modifier.repack_message .. msg
end
-- Send a message to a recipient, applying the pending changes
-- Note that if the modification table is not specified,
-- it will be automatically returned
return {action = "accept"}
end
|
The message being checked will be modified: all the unwanted parts will be removed, archived and sent to the recipient as an attachment.
The archive in which the unwanted elements of the message will be enclosed will be protected with the password specified as the value of the ctx.modifier.repack_password variable. Note that the password specified in the RepackPassword parameter in the configuration file will not be valid in this case.
Tables Used in Scripts
Table MilterContext
This table is used as an input argument of the milter_hook function. It contains the information about the email message being processed (fields, structure, headers, body, information about the sender and the recipient, information about the SMTP session).
Field
|
Description
|
Data type
|
session_id
|
Identifier of the client session during which messages from this client are processed.
|
String
|
sender
|
Information about the sender of the email message.
|
Table MilterSender
|
helo
|
The welcome HELO/EHLO string received from the SMTP client that had sent the email message, or nil if the string is missing/unknown (not provided by the MTA)
|
String
|
from
|
Sender’s email address without angle brackets (for example: user@domain.com)
|
String
|
to
|
Recipients’ email addresses without angle brackets
|
Table RcptTo
|
message
|
Email message (with the body and all headers)
|
Table MimeMessage
|
modifier
|
The MilterModifier table that contains all changes to be applied to a message if the "accept" action is generated according to the scanning results in the MilterResult table.
|
Table MilterModifier
|
gen
|
The MilterGenerator table used for generating special headers, such as X-Antivirus
|
Table MilterGenerator
|
spf
|
The SPF table used for performing SPF checks of the sender
|
Table SPF
|
Overridden metamethods: None
|
Table MilterSender
This table is used as the sender field of the MilterContext table. It contains the information about the email sender.
Field
|
Description
|
Data type
|
hostname
|
Sender’s host name (FQDN)
|
String
|
family
|
Connection type as a string
•"U"—unknown type
•"L"—connection via a UNIX socket
•“4”—connection via IPv4
•"6"—connection via IPv6 |
String
|
port
|
Port number
|
Integer
|
ip
|
IP address of the sender's host, or nil if the IP address is missing or unknown (not provided by the MTA)
|
Table IpAddress
|
Overridden metamethods: None
|
Table MilterResult
The table represents the result returned by the milter_hook function.
Field
|
Description
|
Data type
|
action
|
String with description of the action that should be applied to the message:
•"accept"—accept (i.e. allow MTA to send the message to the recipient);
•"discard"—discard the message without notifying the sender
•"reject"—reject the message and return the SMTP 5** code to the sender;
•"tempfail"—reject the message and return the SMTP 4** code to the sender;
•"replycode"—send the SMTP response, that is specified in the code field, to the sender.
Required field.
|
String
|
code
|
A three-digit SMTP response code to be sent to the sender, for example, "541".
Optional field. Only used if action = "replycode".
|
String
|
text
|
String with a response text sent to the sender, for example, "User not local or invalid address – Relay denied".
Optional field. Only used if action = "replycode".
|
String
|
message
|
String with a response text sent to the sender, for example, "Message rejected as spam".
Optional field. Only used if action = "reject".
|
String
|
modifications
|
Table describing the changes to be applied to the email message before sending it to the recipient.
Optional field. Only used if action = "accept".
|
Table MilterModifications
|
added_recipients
|
List of email addresses of additional message recipients.
Optional field. Only used if action = "accept".
|
String array
|
deleted_recipients
|
List of email addresses to be excluded from the list of the message recipients.
Optional field. Only used if action = "accept".
|
String array
|
incident
|
Description of the incident in the registered event of the Mail type.
•If the field is a string, the contents of this string will be transmitted to the incident_text field of the Mail event and the event will be registered;
•If the field is boolean and is equal to false, then the incident_text field of the Mail event will be absent and the event will not be registered;
•If the field is boolean and is equal to true, then the incident_text field of the Mail event will be filled in automatically and the event will be registered, if the value of incident_text is not empty. |
String or boolean value
|
Overridden metamethods: None
|
Table MilterModifications
The table is used for description of all changes to be made to the email message once the decision to deliver it to a recipient has been taken (the accept action has been selected). All fields of the table are optional; if a field value is missing, the action specified in this field is not applied to the message:
Field
|
Description
|
Data type
|
new_body
|
New message body (without headers) which should be used to replace the body of the message being processed.
|
String
|
added_fields
|
Headers to be added to the message being processed.
|
Array of MilterAddedField tables
|
changed_fields
|
Headers to be modified or removed from the message being processed.
|
Array of MilterChangedField tables
|
Overridden metamethods: None
|
Table MilterAddedField
The table contains the description of headers to be added to the message being processed.
Field
|
Description
|
Data type
|
name
|
Header name
|
String
|
value
|
Header value
|
String
|
Overridden metamethods: None
|
Table MilterChangedField
The table contains the description of the headers to be modified in the message being processed (or removed from it).
Field
|
Description
|
Data type
|
name
|
Header name
|
String
|
index
|
Ordinal number of the header with the name name in the message to be changed (counting from 1)
|
Number
|
value
|
New value of the header (or an empty string "" to remove the header).
|
String
|
Overridden metamethods: None
|

|
For description of the changes to be made to the message after processing, it is recommended not to fill in the MilterModifications table directly. You should use methods from the MilterModifier table instead that can be received from the context.
|
Table MilterGenerator
The table contains secondary methods for generating the X-Antivirus and X-Authentication-Results standard headers.
Field
|
Description
|
Data type
|
х_antivirus_header_field
|
The function is used for generating the X-Antivirus header that contains the information upon the anti-virus components involved in the scanning of the message and returns the HeaderField table or nil (if the message has not been scanned yet).
The name field in the HeaderField has the fixed value (X-Antivirus).
|
Function
|
authentication_results_header_field
|
The function is used for generating the Authentication-Results header which contains the information upon the results of DKIM and SPF checks. It takes as an optional argument the authserv_id string which is the ID of the server in the generated header. By default the value of authserv_id matches the name of the host on which Dr.Web MailD is running.
The function returns the HeaderField table.
The name field in the HeaderField has the fixed value (Authentication-Results).
|
Function
|
Overridden metamethods: None
|
Table MilterModifier
The table is used for scheduling changes to the message after it is processed (if it is sent to the recipient).
Field
|
Description
|
Data type
|
add_header_field
|
Function that schedules an action to add a new header to the email message.
Receives two mandatory arguments:
•name is the header name as a string;
•value is the header value as a string.
The value will be encoded according to RFC 2047.
|
Function
|
change_header_field
|
Function that schedules an action to change (or remove) the specified header.
Receives two mandatory arguments:
•name is the header name as a string;
•value is the header value as a string.
If the message has multiple headers with the specified name, the function will change the value of the first header with such name. In case of multiple value changes of the same header, only the last value is kept. If the value is an empty string "", the header name will be removed from the message.
The value will be encoded according to RFC 2047.
|
Function
|
modifications
|
Function that returns the MilterModifications table containing the whole list of changes scheduled to be made to the email message. Does not have any arguments.
|
Function
|
repack
|
Function that schedules the repacking of the specified message part (or the whole message, if a part is not specified or the specified part does not exist). During the repacking, the specified parts will be added to archive with a password.
Accepts the optional argument path or iterator:
•path is a path to the scanned email attachment to be archived. If the path is not specified or if the specified path is not valid, the whole message is archived.
•iterator is a message part iterator, returned by the functions threats, urls, attachments, files, parts, leaf_parts, and text_parts of the MimePart table. In this case, all parts of the message returned by the iterator will be scheduled for repacking.
If the function argument is not specified or if the specified path is not valid, the whole message is archived.
Examples:
-- Schedule the entire message to be repacked
-- to an archive with a password
ctx.modifier.repack()
-- Schedule some parts of a message at the specified path
-- (or the entire message if the part does not exist)
-- to be repacked to an archive with a password
ctx.modifier.repack('/1/2/3')
-- Schedule all message parts that contain executables
-- to be repacked to an archive with a password
ctx.modifier.repack(ctx.message.files{name='*.exe'})
-- Schedule all ZIP attachements to be repacked
-- to an archive with a password
ctx.modifier.repack(ctx.message.attachments{name='*.zip'})
|
|
Function
|
repack_archive_name
|
Name of the archive for packing malicious or unwanted items of the message. By default, "quarantine.zip".
|
String
|
repack_password
|
Password for the archive protection. If it is not specified, the password specified in the configuration file is used (RepackPassword parameter).
|
String
|
repack_message
|
Arbitrary message about the reasons of the message (or its parts) repacking. It is added to the final message (can be absent).
|
String
|
templates_dir
|
Path to a directory, where the repacking template is stored. The path is relative referring to a path specified in the configuration file (TemplatesDir parameter). The default value is "milter" (that is, templates from the milter subdirectory will be used).
|
String
|
cure
|
Function that schedules the curing of an attachment.
Accepts the optional argument path or iterator:
•path is the path to the scanned email attachment. The cure(path) function returns true if the attachment is harmless or has been cured. If the attachment cannot be cured, the function returns false.
•iterator is a message part iterator returned by the functions threats, urls, attachments, files, parts, leaf_parts, and text_parts of the MimePart table. In this case, all parts of the message returned by the iterator will be scheduled for curing. The cure(iterator) function returns true if all the attachments are harmless or have been cured. If at least one attachment cannot be cured, the function returns false.
Identical to calling cure(ctx.message.leaf_parts()) if the function argument is not specified. Returns true if all the attachments are harmless or have been cured. If at least one attachment cannot be cured, the function returns false.
|
Function
|
cure_or_repack
|
Function that schedules the curing of an attachment. If it cannot be cured, the attachment is repacked. During the repacking, the specified parts will be added to an archive with a password.
Accepts the optional argument path or iterator:
•path is the path to the scanned email attachment. The cure_or_repack(path) function returns true if the attachment is harmless or has been cured. If the attachment cannot be cured, the function returns false and schedules the attachment to be repacked.
•iterator is a message part iterator returned by the functions threats, urls, attachments, files, parts, leaf_parts, and text_parts of the MimePart table. In this case, all parts of the message returned by the iterator will be scheduled for curing. The cure_or_repack(iterator) function returns true if all the attachments are harmless or have been cured. If at least one attachment cannot be cured, the function returns false and schedules all the incurable attachment to be repacked.
Identical to calling cure_or_repack(ctx.message.leaf_parts()) if the function argument is not specified. Returns true if all the attachments are harmless or have been cured. If at least one attachment cannot be cured, the function returns false and schedules all the incurable attachment to be repacked.
|
Function
|
Overridden metamethods: None
|
To access this table, you should use the modifier field of the MilterContext table. For example:
function milter_hook(ctx)
-- Schedule adding a new header
-- at the end of the list of headers
ctx.modifier.add_header_field("X-Name", "Value")
-- Schedule changing the "Subject" field value to "New value"
ctx.modifier.change_header_field("Subject", "New value")
-- Schedule repacking messages to an archive with a password
ctx.modifier.repack()
-- Return verdict via the milter protocol (table MilterResult)
-- and apply all pending changes of the message
return {action = "accept"}
end
|
In the example below you can see how to fill in the MilterResult table (and its modifications field, that is the MilterModifications table) directly, without using the MilterModifier table:
-- Enable message sending to recipients by adding
-- the "X-Checked: True" header
function milter_hook(ctx)
return {
action = "accept",
modifications = {
added_fields = {
{
name = "X-Checked",
value = "True"
}
}
}
}
end
|
The next example shows how to return the accept verdict despite the changes made to the MilterModifier table:
function milter_hook(ctx)
…
-- Schedule adding the message header
ctx.modifier.add_header_field('X-Header', 'some value')
…
-- Force return of an empty MilterModifications table
return {action = "accept", modifications = {}}
end
|
Script for Message Processing for the Spamd Interface
Requirements for the Script
The script must contain a global function, that is an entry point in the message scanning module (Dr.Web MailD will call this function for processing all incoming messages). The processing function should match the following call conventions:
1.Function name is spamd_report_hook;
2.The only argument is the SpamdContext table (provides access from the function to the information about the processed email message);
3.The only return value is the completed SpamdReportResult table. The return value defines the response via Spamd.
Below you can see an example of a correct definition of the function which always returns to Dr.Web MailD the verdict that the message must be marked as spam (spam score: 200, minimum score for classifying as spam: 100, message: The message was recognized as spam; here and after the ctx argument is an instance of the SpamdContext table):
-- An example of a trivial realization
function spamd_report_hook(ctx)
return {
score = 200,
threshold = 100,
report = "The message was recognized as spam"
}
end
|
Tables Used in Lua Scripts
Table SpamdContext
The table is used as an input argument of the spamd_report_hook function. It contains the information about the email message being processed (structure, headers, body, information about the sender and the recipient, information about the SMTP session).
Field
|
Description
|
Data type
|
session_id
|
Identifier of the client session during which messages from this client are processed.
|
String
|
message
|
Email message
|
Table MimeMessage
|
Overridden metamethods: None
|
Table SpamdReportResult
The table represents the result returned by the spamd_report_hook function. It passes the results of scanning for spam to Dr.Web MailD, the results should be returned to MTA.
Field
|
Description
|
Data type
|
score
|
Spam rating assigned to the message (for the Exim MTA fills the $spam_score and $spam_score_int variables)
|
Number
|
threshold
|
Threshold point at which a message is classified spam
|
Number
|
report
|
Text result of the message scanning (for the Exim MTA fills the $spam_report variable)
|
String
|
incident
|
Description of the incident in the registered event of the Mail type.
•If the field is a string, the contents of this string will be transmitted to the incident_text field of the Mail event and the event will be registered;
•If the field is boolean and is equal to false, then the incident_text field of the Mail event will be absent and the event will not be registered;
•If the field is boolean and is equal to true, then the incident_text field of the Mail event will be filled in automatically and the event will be registered, if the value of incident_text is not empty. |
String or boolean value
|
Overridden metamethods: None
|
Script for Message Processing for the Rspamd Interface
Requirements for the Script
The script must contain a global function serving as an entry point for the message scanning module (Dr.Web MailD will call this function for processing a newly received message). The processing function should match the following call conventions:
1.Function name is rspamd_hook;
2.The only argument is the RspamdContext table (provides access from the function to the information about the processed email message; see the table description below);
3.The only return value is the completed RspamdResult table (see the table description below). The return value defines the response via RspamD.
An example of the correct definition of the script (here and after the ctx argument is an instance of the RspamdContext table):
-- An example of a trivial realization
function rspamd_hook(ctx)
return {
score = 200,
threshold = 100
}
end
|
Example
The script below returns the recommended actions for MTA as well as the RspamdSymbol containing the spam score with a brief comment (signs of spam detected in the message and the number of points corresponding to each sign):
function rspamd_hook(ctx)
return {
score = 1080,
threshold = 100,
action = "REJECT:Malicious message"
symbols = {
{
name = "Threat found",
score = 1000
},
{
name = "Spam score by the third-party anti-spam library",
score = 80
}
}
}
end
|
Tables Used in Lua Scripts
Table RspamdContext
The table is used as an input argument of the rspamd_hook function. It contains the information about the email message being processed.
Field
|
Description
|
Data type
|
session_id
|
Identifier of the client session during which messages from this client are processed.
|
String
|
sender
|
Information about the message sender
|
Table RspamdSender
|
helo
|
The HELO/EHLO string received from the SMTP client, or nil if the string is missing/unknown (not provided by the MTA)
|
String
|
from
|
Sender’s email address (without angle brackets, for example: user@domain.com) or nil if the address is missing/unknown (not provided by the MTA)
|
String
|
to
|
Recipients’ email addresses without angle brackets
|
Table RcptTo
|
message
|
Email message
|
Table MimeMessage
|
spf
|
The SPF table used for performing SPF checks of the sender
|
Table SPF
|
Overridden metamethods: None
|
Table RspamdSender
The table contains the information about the message sender.
Field
|
Description
|
Data type
|
hostname
|
Name (FQDN) of the sender's host, or nil if missing or unknown (not provided by the MTA)
|
String
|
ip
|
IP address of the sender's host, or nil if missing or unknown (not provided by the MTA)
|
Table IpAddress
|
Overridden metamethods: None
|
Table RspamdResult
The table represents the result returned by the rspamd_hook function. Contains the message scanning report.
Field
|
Description
|
Data type
|
score
|
Spam score assigned to the message after scanning (for the Exim MTA fills the $spam_score and $spam_score_int variables)
|
Number
|
threshold
|
Minimum spam score above which the message is treated as spam
|
Number
|
action
|
Optional field. Action recommended for MTA as a result of the message scanning (for the Exim MTA fills the $spam_action variable)
|
String
|
symbols
|
Optional field. Array of RspamdSymbol tables for determining the reason of assigning the number of spam points specified in the score field
|
Array of RspamdSymbol tables
|
incident
|
Description of the incident in the registered event of the Mail type.
•If the field is a string, the contents of this string will be transmitted to the incident_text field of the Mail event and the event will be registered;
•If the field is boolean and is equal to false, then the incident_text field of the Mail event will be absent and the event will not be registered;
•If the field is boolean and is equal to true, then the incident_text field of the Mail event will be filled in automatically and the event will be registered, if the value of incident_text is not empty. |
String or boolean value
|
Overridden metamethods: None
|
Table RspamdSymbol
The table describes the signs of spam detected in the message (for example, file with a threat, unwanted URL, and so on) for which points have been added to the spam score.
Field
|
Description
|
Data type
|
name
|
Name of the detected sign of spam
|
String
|
score
|
Number of points added to the spam score upon detection of this sign
|
Number
|
description
|
A brief description of the detected sign of spam (optional field)
|
String
|
Overridden metamethods: None
|
Script for Message Processing in SMTP Mode
Requirements for the Script
The script must contain a global function that is an entry point in the message scanning module (Dr.Web MailD will call this function for processing newly received message). The processing function should match the following call conventions:
1.Function name is smtp_hook;
2.The only argument is the SmtpContext table (provides access from the function to the information about the processed email message);
3.The only returned value is the SmtpResult completed table. The returned value defines a verdict about the scanned message: accept, reject, change, or discard, as well as actions to be applied (possibly) to the message if it is accepted.
Below you can see an example of a correctly defined function that always returns to Dr.Web MailD the Accept verdict for all messages received for scanning via SMTP mode (here and after the ctx argument is an instance of the SmtpContext table):
function smtp_hook(ctx)
return {action = "accept"}
end
|
SMTP mode allows for email modification, such as: adding new headers, modifying headers, adding or removing email recipients, modifying the email body. SMTP mode also supports integration with the Dr.Web vxCube web service for analyzing email attachments. Verdicts received from Dr.Web vxCube can be used for determining which action is to be applied to the email.
Example
The script below returns the Accept verdict for all email messages to Dr.Web MailD and adds the "X-Checked: True" header field to all messages:
function smtp_hook(ctx)
return {
action = "accept",
modifications = {
added_fields = {
{
name = "X-Checked",
value = "True"
}
}
}
}
end
|
In order to form the modifications table, you can use the auxiliary MilterModifier object of the SmtpContext table, for example:
function smtp_hook(ctx)
local modifier = ctx.modifier
-- Schedule appending a new field to the end of the header
modifier.add_header_field("X-Name", "Value")
-- Schedule changing the "Subject" field value to "New value"
modifier.change_header_field("Subject", "New value")
-- Schedule repacking messages to an archive with a password
modifier.repack()
-- Apply all pending changes to the message and send it
-- modifications do not have to be specified, the changes will be taken directly from modifier
return { action = "accept", modifications = modifier.modifications() }
end
|
Tables Used in Scripts
Table SmtpContext
The table is used as an input argument of the smtp_hook function. It contains the information about the email message being processed.
Field
|
Description
|
Data type
|
session_id
|
Identifier of the client session during which messages from this client are processed.
|
String
|
sender
|
Information about the sender of the email message.
|
Table MilterSender
|
helo
|
The HELO/EHLO string received from the SMTP client, or nil if the string is missing/unknown (not provided by the MTA)
|
String
|
from
|
Sender’s address (without angle brackets, for example: "user@domain.com")
|
String
|
to
|
Recipients’ email addresses without angle brackets
|
Table RcptTo
|
message
|
Email message
|
Table MimeMessage
|
modifier
|
The MilterModifier table contains all changes to be made to a message if the "accept" action is generated according to the scanning results in the MilterResult table.
|
Table MilterModifier
|
gen
|
The MilterGenerator table used for generating special headers, such as X-Antivirus
|
Table MilterGenerator
|
spf
|
The SPF table used for performing SPF checks of the sender
|
Table SPF
|
Overridden metamethods: None
|
Table SmtpResult
The table represents the result returned by the smtp_hook function. It contains the descriptions of actions to be applied to the message being checked.
Field
|
Description
|
Data type
|
action
|
String with description of the action that should be applied to the message:
•"accept"—accept (i.e. allow MTA to send the message to the recipient);
•"discard"—discard the message without notifying the sender;
•"tempfail"—reject the message and return the SMTP 4** code to the sender.
Required field.
|
String
|
modifications
|
Table describing the changes to be applied to the email message before sending it to the recipient.
Optional field. Only used if action = "accept".
|
Table MilterModifications
|
added_recipients
|
List of email addresses of additional message recipients.
Optional field. Only used if action = "accept".
|
String array
|
deleted_recipients
|
List of email addresses to be excluded from the list of the message recipients.
Optional field. Only used if action = "accept".
|
String array
|
message
|
String with a response text sent to the sender about the message being rejected. Is returned to the sender with the 541 code is the message is being checked synchronously.
Optional field. Only used if action = "reject".
|
String
|
incident
|
Description of the incident in the registered event of the Mail type.
•If the field is a string, the contents of this string will be transmitted to the incident_text field of the Mail event and the event will be registered;
•If the field is boolean and is equal to false, then the incident_text field of the Mail event will be absent and the event will not be registered;
•If the field is boolean and is equal to true, then the incident_text field of the Mail event will be filled in automatically and the event will be registered, if the value of incident_text is not empty. |
String or boolean value
|
Overridden metamethods: None
|
Tables Describing the Message Structure
Table RcptTo
The table contains an array of email addresses of the message recipients (without angle brackets) that encountered in the RCPT TO command of the SMTP protocol as well as the following additional information:
Field
|
Description
|
Data type
|
search
|
The function that checks for the presence of at least one address corresponding to at least one of the specified templates in the address array.
Accepts one mandatory patterns argument, i.e. search patterns, i.e. one (string) or several (array of strings) regular expressions in the Perl syntax (PCRE).
Returns a Boolean value:
•true—if an address corresponding to at least one template has been found;
•false—if no address corresponding to at least one template has been found.
Not case-sensitive.
|
Function
|
all_match
|
The function that checks whether all addresses correspond to at least one of the specified templates in the address array.
Accepts one mandatory patterns argument, i.e. search patterns, i.e. one (string) or several (array of strings) regular expressions in the Perl syntax (PCRE).
Returns a Boolean value:
•true—all addresses fully correspond to at least one template;
•false—no address fully corresponds to any of the templates
Not case-sensitive.
|
Function
|
Overridden metamethods: None
|
Table MimeMessage
The table describes the email message being processed as a whole (includes the same fields as the MimePart table and some additional information)
Field
|
Description
|
Data type
|
dkim
|
DKIM signatures (see RFC 6376) of the email message
|
The DKIM table
|
raw
|
Email message received from the client
|
String
|
spam
|
Report about the results of the message scanning for spam signs
|
Table Spam
|
from
|
The From header value, or nil if From is absent in the message
|
Table From
|
to
|
The To header value, or nil if To is absent in the message
|
Table To
|
date
|
The Date header value, or nil if Date is absent in the message
|
String
|
message_id
|
The Message-ID header value, or nil if Message-ID is absent in the message
|
String
|
subject
|
The Subject header value, or nil if Subject is absent in the message
|
String
|
user_agent
|
The User-Agent header value, or nil if User-Agent is absent in the message
|
String
|
vxcube_analysis
|
Message analysis result from Dr.Web vxCube. The field is present only when in SMTP mode.
|
Array of VxcubeAnalysis tables
|
(the next fields are similar to those of the MimePart table; they describe the root MIME part)
|
Overridden metamethods: None
|
Table MimePart
The table describes a part of the email message:
Field
|
Description
|
Data type
|
header
|
Header of the message
|
Table MimeHeader
|
body
|
Body of the part, or nil if there are attached parts.
|
Table MimeBody
|
part
|
Attached (to the current message part) parts as an array of tables. If there are no attached parts, the array is empty.
|
Array of MimePart tables
|
content_disposition
|
Contents of the Content-Disposition header, or nil, if this header is absent in the part.
|
Table ContentDisposition
|
content_id
|
Contents of the Content-ID header, or nil, if this header is absent in the part.
|
String
|
content_type
|
Contents of the Content-Type header, or nil, if this header is absent in the part.
|
Table ContentType
|
name
|
Attachment name, or nil if the part is not an attachment
|
String
|
part_at
|
Function that receives the path argument—the path to a child part of the message. Returns an attached message part (table MimePart) that is located at the specified path.
Path is a string that looks like "/1/2/3", that is root_part. part [1]. part [2]. part [3]. Paths that look like "", "/", "//", and so on (without numbers) correspond to the message part that this function is called from (i.e. root_part). If there is no child part at the specified path, as well as when the path is incorrect, the function returns nil.
|
Function
|
threats
|
Function that takes filter as an optional argument. The function returns a single value—an iterator function. Using this iterator, it is possible to go through all threats that are located in this part of the message and in its attached parts and that meet the specified filter condition. The iterator function does not have any arguments and returns two values:
•the Virus table;
•relative path to the message part that contains the detected threat.
As the filter argument, you can use:
•the ThreatFilter table;
•arbitrary predicate function that receives the only Virus argument and returns a Boolean value:
otrue—if the argument meets the condition (being a threat);
ofalse—if the argument does not meet the condition (being a threat) |
Function
|
urls
|
Function that takes filter as an optional argument. The function returns a single value—an iterator function. Using this iterator, it is possible to go through all URLs that are located in this part of the message and in its attached parts and that meet the specified filter condition. The iterator function does not have any arguments and returns two values:
•the Url table;
•relative path to the message part that contains the found URL.
As the filter argument, you can use:
•the UrlFilter table;
•arbitrary predicate function that receives the only Url argument and returns a Boolean value:
otrue—if the argument meets the condition (is unwanted);
ofalse—if the argument does not meet the condition (is not unwanted) |
Function
|
attachments
|
Function that takes filter as an optional argument. The function returns a single value—an iterator function. Using this iterator, it is possible to go through all attachments that are located in this part of the message and in its attached parts and that meet the specified filter condition. The iterator function does not have any arguments and returns two values:
•the MimePart table;
•relative path to the message part that contains the found attachment.
As the filter argument, you can use:
•the PartFilter table;
•arbitrary predicate function that receives the only MimePart argument and returns a Boolean value:
otrue—if the argument meets the condition;
ofalse—if the argument does not meet the condition |
Function
|
files
|
Function that takes filter as an optional argument. The function returns a single value—an iterator function. Using this iterator, it is possible to go through all files that are located in this part of the message and in its attached parts (including archives) and that meet the specified filter condition. The iterator function does not have any arguments and returns two values:
•file name as a string;
•relative path to the message part that contains the found file.
As the filter argument, you can use:
•the FileFilter table;
•arbitrary predicate function that receives a file name as a string and returns a Boolean value:
otrue—if the argument meets the condition;
ofalse—if the argument does not meet the condition |
Function
|
parts
|
Function that takes filter as an optional argument. The function returns a single value—an iterator function. Using this iterator, it is possible to go through all message parts that are located in this part of the message and in its attached parts and that meet the specified filter condition. The iterator function does not have any arguments and returns two values:
•the MimePart table;
•relative path to the message part.
As the filter argument, you can use:
•the PartFilter table;
•arbitrary predicate function that receives the MimePart table and returns a Boolean value:
otrue—if the argument meets the condition;
ofalse—if the argument does not meet the condition |
Function
|
leaf_parts
|
Function that takes filter as an optional argument. The function returns a single value—an iterator function. Using this iterator, it is possible to go through all leaf parts that are located in this part of the message and in its attached parts and that meet the specified filter condition. The iterator function does not have any arguments and returns two values:
•the MimePart table;
•relative path to the message part.
As the filter argument, you can use:
•the PartFilter table;
•arbitrary predicate function that receives the MimePart table and returns a Boolean value:
otrue—if the argument meets the condition;
ofalse—if the argument does not meet the condition. |
Function
|
text_parts
|
Function that takes filter as an optional argument. The function returns a single value—an iterator function. Using this iterator, it is possible to go through all text parts that are located in this part of the message and in its attached parts and that meet the specified filter condition. The iterator function does not have any arguments and returns two values:
•the MimePart table;
•relative path to the message part.
As the filter argument, you can use:
•the PartFilter table;
•arbitrary predicate function that receives the MimePart table and returns a Boolean value:
otrue—if the argument meets the condition;
ofalse—if the argument does not meet the condition. |
Function
|
scan_reports
|
Function that takes filter as an optional argument. The function returns a single value—an iterator function. Using this iterator, it is possible to go through all reports of scanning this part of the message and its attached parts, that meet the specified filter condition.
The iterator function does not have any arguments and returns single value: the ScanReport table.
As the filter argument, you can use:
•the ScanReportFilter table;
•arbitrary predicate function that receives the ScanReport table and returns a Boolean value:
otrue—if the argument meets the condition;
ofalse—if the argument does not meet the condition. |
Function
|
has_url
|
Function that takes filter as an optional argument. (see description of the urls function above).
Returns a Boolean value:
•true—if this part of the message and its attached parts contain a URL that meets the condition filter;
•false—if neither the part of the message nor the attached parts contain a URL that meets the condition filter.
Examples:
if ctx.message.has_url() then
-- at least one URL has been found in the email message
end
if ctx.message.has_url{category = "adult_content"} then
-- an adult content link has been found
end
if ctx.message.has_url{category = {"adult_content", "social_networks"}} then
-- an "adult_content" or a "social_networks" link has been found
end
if ctx.message.has_url{category = "black_list"} then
-- a link to a blacklisted resource been found
end
if ctx.message.has_url{host = "example.com"} then
end
end
if ctx.message.has_url{host_not = "*example.com"} then
-- a link detected with a host that does not correspond to the "*example.com" template
end
if ctx.message.has_url(function(url) return port > 80 end) then
-- a link whose port number is more than 80 has been found
end
|
|
Function
|
has_threat
|
Function that takes filter as an optional argument.(see description of the threats function above).
Returns a Boolean value:
•true—if this part of the message and its attached parts contain a threat that meets the condition filter;
•false—if neither the part of the message nor the attached parts contain a threat that meets the condition filter.
Examples:
if ctx.message.has_threat() then
-- the message contains at least one threat of any category
end
if ctx.message.has_threat({category = "known_virus"}) then
-- the message contains at least one threat of the "known_virus" category
end
if ctx.message.has_threat{category = "known_virus"} then
-- the same
end
if ctx.message.has_threat({category = {"known_virus", "joke"}}) then
-- the message contains at least one threat of the "known_virus" or "joke" category
end
if ctx.message.has_threat{category_not = "joke"} then
-- the message contains a threat of any category except "joke"
end
|
|
Function
|
has_file
|
Function that takes filter as an optional argument. (see description of the files function above).
Returns a Boolean value:
•true—if this part of the message and its attached parts contain a file that meets the condition filter (including files in archives);
•false—if neither the part of the message nor the attached parts contain a URL that meets the condition filter.
Examples:
if ctx.message.has_file() then
-- at least one file has been found in the email message
end
if ctx.message.has_file{name = "*.exe"} then
-- at least one exe file has been found in the email message
end
|
|
Function
|
has_part
|
Function that takes filter as an optional argument. (see description of the parts function above).
Returns a Boolean value:
•true—if this part of the message and its attached parts contain a part that meets the condition filter;
•false—if neither the part of the message nor the attached parts contain a part that meets the condition filter. |
Function
|
has_scan_report
|
Function that takes filter as an optional argument. (see description of the scan_reports function above).
Returns a Boolean value:
•true—if this part of the message and its attached parts contain a scan report that meets the condition filter;
•false—if neither the part of the message nor the attached parts contain a scan report that meets the condition filter.
For usage examples, see the description of the ScanReportFilter table.
|
Function
|
search
|
Function that searches for text in this message section using a regular expression (PCRE). Receives a regular expression (string). Note that if you use strings in the quotation marks, the slash character must be escaped.
Returns a Boolean value:
•true—if a match with the specified regular expression has been found in this section or in a child part;
•false—if a match with the specified regular expression has not been found in this section or in a child part |
Function
|
Overridden metamethods: None
|
Table From
A table describing the From email message header. It contains the list of email addresses extracted from the header (array of strings) and the following additional information.
Field
|
Description
|
Data type
|
search
|
The function that checks for the presence of at least one address corresponding to at least one of the specified templates in the address array.
Accepts one mandatory patterns argument, i.e. search patterns, i.e. one (string) or several (array of strings) regular expressions in the Perl syntax (PCRE).
Returns a Boolean value:
•true—an address that fully corresponds to at least one template has been found;
•false—no address that fully corresponds to at least one template has been found.
Not case-sensitive.
|
Function
|
all_match
|
The function that checks whether all addresses correspond to at least one of the specified templates in the address array.
Accepts one mandatory patterns argument, i.e. search patterns, i.e. one (string) or several (array of strings) regular expressions in the Perl syntax (PCRE).
Returns a Boolean value:
•true—all addresses fully correspond to at least one template;
•false—no address fully corresponds to at least one template.
Not case-sensitive.
|
Function
|
Overridden metamethods:
•__tostring is the function that returns the decoded header value;
•__concat is the function that concatenates the decrypted value of the header with a string. |
Table To
The table describes the To email message header. It contains the same fields and methods as the From table.
Table ContentType
The table describes the Content-Type header in the message part.
Field
|
Description
|
Data type
|
type
|
MIME type of the message part
|
String
|
subtype
|
Subtype of the message part
|
String
|
param
|
Header parameters in the form of a table array with the following fields:
•name is a parameter name (string);
•value is parameter value (string). |
Table array
|
Overridden metamethods:
•__tostring is the function that returns the decoded header value;
•__concat is the function that concatenates the decrypted value of the header with a string. |
Table ContentDisposition
The table describes the Content-Disposition header in the message part.
Field
|
Description
|
Data type
|
type
|
View type of the message part
|
String
|
param
|
Header parameters in the form of a table array with the following fields:
•name is a parameter name (string);
•value is parameter value (string). |
Table array
|
Overridden metamethods:
•__tostring is the function that returns the decoded header value;
•__concat is the function that concatenates the decrypted value of the header with a string. |
Table Spam
Table contains the spam check report for the specified message.
Field
|
Description
|
Data type
|
type
|
Message type (spam status). Possible values:
•"legit"—the message is not spam;
•"spam"—the message is spam;
•"virus"—the third-party heuristic analyzer has detected a virus in the message body;
•"bounce"—the message contains a report on a negative delivery (DSN) sent to the sender of the original message;
•"suspicious"—a suspicious message;
•"pce"—a “professional” commercial (advertising) message, send by a valid subscription service;
•"mce"—a commercial (advertising) message, not sent by valid subscription services, but with a way to unsubscribe;
•"dce"—“dirty” commercial (advertising) message with no way of unsubscribing;
•"community"—a message from a social network;
•"transactional"—a transaction-related message (registration, purchase of services or goods);
•"phishing"—a fraudulent message;
•"scam"—a fraudulent message (a scam message). |
String
|
score
|
Spam rating assigned to the message
|
Number
|
normalized_score
|
Number of spam points score normalized in the interval [0, 1)
|
Number
|
reason
|
Encrypted string that contains an explanation why the email message is spam
|
String
|
version
|
Third-party anti-spam library version
|
String
|
Overridden metamethods: None
|
Table Virus
The table describes a threat.
Field
|
Description
|
Data type
|
type
|
Threat type (according to the Doctor Web classification):
•"known_virus"—a known threat (a threat that has a description in the virus databases);
•"virus_modification"—a modification of the known threat;
•"unknown_virus"—an unknown threat, suspicious object;
•"adware"—an advertising program;
•"dialer"—a dialer program;
•"joke"—a joke program;
•"riskware"—a potentially dangerous program;
•"hacktool"—a hacktool. |
String
|
name
|
Threat type (according to the Doctor Web classification)
|
String
|
Overridden metamethods: None
|
Table Url
Table that describes an URL.
Field
|
Description
|
Data type
|
scheme
|
Scheme (protocol) prefix, for example, "http"
|
String
|
host
|
Host name or IP address, for example, "example.com"
|
String
|
port
|
Port number, for example, 80. If it is absent in the URL, the value is nil.
|
Number
|
path
|
Path to a resource, for example, "index.html". If it is absent in the URL, the value is nil.
|
String
|
categories
|
Array of categories to which the URL is placed based on the result of scanning. Possible values:
•"infection_source"—an infection source;
•"not_recommended"—a source that is not recommended for visiting;
•"adult_content"—adult content;
•"violence"—violence;
•"weapons"—weapons;
•"gambling"—gambling;
•"drugs"—drugs;
•"obscene_language"—obscene language;
•"chats"—chats;
•"terrorism"—terrorism;
•"free_email"—free email;
•"social_networks"—social networks;
•"owners_notice"—websites added due to a notice from copyright owner;
•"online_games"—online games;
•"anonymizers"—anonymizers;
•"cryptocurrency_mining_pools"—cryptocurrency mining pools;
•"jobs" — job search sites;
•"black_list"—black list (resources considered non-recommended by the mail server administrator). |
Table of strings
|
legal_url
|
If the URL belongs to the owners_notice category, the field contains the URL to the owner’s website; otherwise, it is nil.
|
String
|
Overridden metamethods:
•__toString—the function returns the Url content as a string (in the UTF-8);
•__concat—the function concatenates the URL string value and another string. |
Table ThreatFilter
The table describes a filter for threats. All fields are optional.
Field
|
Description
|
Data type
|
category
|
List of categories that the threat is expected to match (not case-sensitive). See the list of categories in description of the type field of the Virus table.
|
String or table of strings
|
category_not
|
List of categories that the threat is not expected to match (not case-sensitive).
|
String or table of strings
|
Overridden metamethods: None
|
If the filter field is not specified (the value is nil), any threat matches the filter. If several filter fields are specified, then the condition is combined by a conjunction (logical AND). If the filter field is a table (list), the object must match at least one of the table (list) items.
Usage examples:
1.Write to the log all the names of the threats detected in the message:
function milter_hook(ctx)
…
for virus in ctx.message.threats() do
dw.notice("threat found: " .. virus.name)
end
…
end
|
2.Write to the log the names the of threats that match the category filter, and the names of the message parts where the threats have been detected:
function milter_hook(ctx)
…
for v, p in ctx.message.threats({category = "known_virus"}) do
dw.notice("found " .. v.name .. " in " .. ctx.message.part_at(p).name(p))
end
…
end
|
3.Write to the log the threat names that match the predicate function, and the names of the message parts where the threats have been detected:
function milter_hook(ctx)
…
local function eicar_filter(v)
return v.name == "EICAR Test File (NOT a Virus!)"
end
for v, p in ctx.message.threats(eicar_filter) do
dw.notice("found " .. v.name .. " in " .. ctx.message.part_at(p).name(p))
end
…
end
|
Table UrlFilter
The table describes the filter applied to URLs (similar to the table ThreatFilter above); all its fields are optional:
Field
|
Description
|
Data type
|
category
|
List of categories that the URL must match (not case-sensitive). See the list of categories in description of the categories field of the Url table.
|
String or table of strings
|
category_not
|
List of categories that the URL cannot match (not case-sensitive).
|
String or table of strings
|
text
|
Text that must match the URL
|
String or table of strings
|
text_not
|
Text that cannot match the URL
|
String or table of strings
|
host
|
Host (domain) that must be present in the URL
|
String or table of strings
|
host_not
|
Host (domain) that cannot be present in the URL
|
String or table of strings
|
Overridden metamethods: None
|
If the filter field is not specified (the value is nil), any threat matches the filter. If several filter fields are specified, then the condition is combined by a conjunction (logical AND). If the filter field is a table (list), the object must match at least one of the table (list) items.
Usage examples:
1.Write to the log all the URLs found in the message:
function milter_hook(ctx)
…
for url in ctx.message.urls() do
dw.notice("url found: " .. url)
end
…
end
|
2.Write to the log the URLs that match the category, and names of the message parts where the URLs have been found:
function milter_hook(ctx)
…
for u, p in ctx.message.urls{category = "adult_content"} do
dw.notice("found " .. u.text .. " in " .. ctx.message.part_at(p).name(p))
end
…
end
|
Table FileFilter
The table describes the filter applied to files (similar to the table ThreatFilter above). All fields are optional.
Field
|
Description
|
Data type
|
name
|
A character set or a wildcard that the name of the file is expected to match. For example: "*.exe", "eicar.txt".
Not case-sensitive.
|
String or table of strings
|
name_re
|
A regular expression (PCRE) that the file name is expected to match. For example: ".*\\.zip", [[.*\.zip]].
Not case-sensitive. Note that if you use strings in the quotation marks, the slash character must be escaped.
|
String or table of strings
|
name_not
|
A character set or a wildcard that the name of the file is not expected to match.
Not case-sensitive.
|
String or table of strings
|
name_re_not
|
A regular expression (PCRE) that the file name is expected to match.
Not case-sensitive. Note that if you use strings in the quotation marks, the slash character must be escaped.
|
String or table of strings
|
Overridden metamethods: None
|
If several filter fields are specified, the condition is combined by conjunction (logical AND). If the filter field is a table (array), the object must match at least one of the table (array) items. If the filter field is not specified (the value is nil), any file matches the filter.
Usage example:
Output to the log the the names of the parts that contain files with an extension .exe.
function milter_hook(ctx)
…
for f, p in ctx.message.files{name = "*.exe"} do
local where = ctx.message.part_at(p).name
if not where or where == "" then where = p end
dw.notice("EXE found in " .. where)
end
…
end
|
Table PartFilter
The table describes the filter for message parts (similar to the table FileFilter above); all its fields are optional.
Field
|
Description
|
Data type
|
name
|
A character set or a wild card that the name of the part is expected to match. For example: "*.exe", "eicar.txt".
Not case-sensitive.
|
String or table of strings
|
name_re
|
A regular expression (PCRE) that the name of the part is expected to match. For example: ".*\\.zip", [[.*\.zip]].
Not case-sensitive. Note that if you use strings in the quotation marks, the slash character must be escaped.
|
String or table of strings
|
content_type
|
A character set that the Content-Type value of the part is expected to match. For example: "image/*".
Not case-sensitive.
|
String or table of strings
|
content_disposition
|
A character set that the Content-Disposition value of the part (attachment) is expected to match. For example: "inline", "attachment".
Not case-sensitive.
|
String or table of strings
|
name_not
|
A character set that the name of the file is not expected to match.
Not case-sensitive.
|
String or table of strings
|
name_re_not
|
A regular expression (PCRE) that the name of the part is not expected to match.
Not case-sensitive. Note that if you use strings in the quotation marks, the slash character must be escaped.
|
String or table of strings
|
content_type_not
|
A character set that the Content-Type value of the part is not expected to match.
Not case-sensitive.
|
String or table of strings
|
content_disposition_not
|
A character set that the Content-Disposition value of the part is not expect to match.
Not case-sensitive.
|
String or table of strings
|
Overridden metamethods: None
|
If the filter field is not specified (the value is nil), any part (attachment) matches the filter. If several filter fields are specified, then the condition is combined by a conjunction (logical AND). If the filter field is a table (array), the object must match at least one of the table (array) items.
Usage examples:
1.Write to the log all the attachments and their MD5 hashes:
function milter_hook(ctx)
…
for a, p in ctx.message.attachments() do
-- the attachment name be an empty string
-- if it is not specified in Content-Type and in Content-Disposition
local name = a.name
if name == "" then name = "at path " .. p end
dw.notice("Attachment: " .. name .. "; md5=" .. a.body.md5)
end
…
end
|
2.Write to the log all the attachments with an .exe extension:
function milter_hook(ctx)
…
for a in ctx.message.attachments{name = "*.exe"} do
dw.notice("EXE attachment: " .. a.name)
end
…
end
|
3.Count and sort by type the images in the email message:
function milter_hook(ctx)
…
local images = {}
for part, path in ctx.message.parts{content_type = "image/*"} do
local subtype = part.content_type.subtype
images[subtype] = (images[subtype] or 0) + 1
end
for t, c in pairs(images) do
dw.notice("Found " .. t .. " images: " .. c)
end
…
end
|
4.Write to the log the list of audio files found in the attachments:
function milter_hook(ctx)
…
for p, path in ctx.message.parts{
content_type = "audio/*",
content_disposition = {"inline", "attachment"}
} do
local name = p.name
if name == "" then name = "<unnamed>" end
dw.notice("Audio file: " .. name)
end
…
end
|
Table ScanReportFilter
The table describes the filter for reports of scanning message parts for threats (similar to the table FileFilter above). Contains the following fields (all fields are optional):
Field
|
Description
|
Data type
|
error
|
Error name to be added to the ScanReport; for instance: "password_protected", "scan_timeout".
Not case-sensitive.
|
String or table of strings
|
error_not
|
Error name that must not be added ScanReport; for instance: "password_protected", "scan_timeout".
Not case-sensitive.
|
String or table of strings
|
Overridden metamethods: None
|
If several filter fields are specified, then the condition is combined by a conjunction (logical AND). If the filter field is a table (array), the scan report must match at least one of the table (array) items. If the filter field is not specified (the value is nil), any scan report matches the filter.
Usage examples:
1.Quarantine the message in case of failed attempts to scan a password-protected archive:
function milter_hook(ctx)
…
if ctx.message.has_scan_report{error = 'password_protected'} then
return
{
action = 'accept', deleted_recipients = ctx.to,
added_recipients = {'quarantine@mail.domain.com'}
}
end
…
end
|
2.Quarantine the message if the scan limits have been exceeded:
function milter_hook(ctx)
…
local limit_errors = {
'archive_level_limit', 'compression_limit',
'container_level_limit', 'mail_level_limit',
'packer_level_limit', 'report_size_limit'
}
if ctx.message.has_scan_report{error = limit_errors} then
return
{
action = 'accept', deleted_recipients = ctx.to,
added_recipients = {'quarantine@mail.domain.com'}
}
end
…
end
|
3.Reject the message in case of scan errors:
function milter_hook(ctx)
…
if ctx.message.has_scan_report{error = '*'} then
return {action = 'reject'}
end
…
end
|
Table MimeHeader
The table describes the message part headers.
Field
|
Description
|
Data type
|
field
|
List of headers and their values
|
Array of HeaderField tables
|
search
|
Function that searches for header by regular expression (PCRE). It takes a regular expression (string) as an argument. The search is performed in all the headers of the message part. Note that if you use strings in the quotation marks, the slash character must be escaped.
Returns a Boolean value:
•true—if the field.name .. ": " .. field.value.decoded string matches the specified regular expression for at least one of the headers;
•false—if the field.name .. ": " .. field.value.decoded string does not match the specified regular expression for at least one of the headers |
Function
|
value
|
Function that returns the value of the specified header. It takes the name of header (string) as an argument.
The function returns the HeaderFieldValue table that corresponds to the first header with the specified name found, or nil if the header has not been found.
|
Function
|
Overridden metamethods: None
|
Table HeaderField
The table describes the message part header.
Field
|
Description
|
Data type
|
name
|
Header name
|
String
|
value
|
Header value
|
Table HeaderFieldValue
|
url
|
List of URLs found in the header value (only for the Subject header), for all other headers—nil
|
Array of Url tables
|
Overridden metamethods: None
|
Table HeaderFieldValue
The table describes the value of the email message header.
Field
|
Description
|
Data type
|
raw
|
Raw (undecoded) header value
|
String
|
decoded
|
Decoded header value
|
String
|
Overridden metamethods:
•__toString—the function returns the HeaderFieldValue content (the decoded field value) as a string;
•__concat—the function concatenates HeaderFieldValue (the decoded field value) and another string. |
Table MimeBody
The table describes the message part body.
Field
|
Description
|
Data type
|
raw
|
Raw (undecoded) body of the message part
|
String
|
decoded
|
Decoded value of the message part body (according to the value of the Content-Transfer-Encoding and Content-Type headers)
|
String
|
text
|
Decoded value of the message part body in the UTF-8 according to the charset parameter of the Content-Type header.
It is present only for the parts with "Content-Type: text/*" or with an empty Content-Type. Otherwise—nil.
|
String
|
scan_report
|
Threat scanning report
|
Table ScanReport
|
url
|
URLs found in the part text as an array of Url tables.
If the text field is absent (nil), the field is empty.
|
Array of Url tables
|
search
|
Function that searches for text in this body using a regular expression (PCRE). Takes a regular expression (string) as an argument. Note that if you use strings in the quotation marks, the slash character must be escaped.
Returns a Boolean value:
•true—if the body is a text and a match has been found;
•false—if no match has not been found in the body |
Function
|
md5
|
MD5 hash of the email message body.
|
String
|
sha1
|
SHA1 hash of the email message body.
|
String
|
sha256
|
SHA256 hash of the email message body.
|
String
|
vxcube_analysis
|
Message analysis result from Dr.Web vxCube. The field is present only when in SMTP mode.
|
Array of VxcubeAnalysis tables
|
Overridden metamethods: None
|
Table ScanReport
The table contains a report about scanning for threats.
Field
|
Description
|
Data type
|
object
|
Name of the scanned object
|
String
|
archive
|
Information about the container, if the scanned object is a container. If the object is not a container, it is nil
|
The Archive table
|
virus
|
List of detected threats
|
Array of Virus tables
|
error
|
In case of an error, it contains a string with a scan error. Otherwise, it is nil. Allowed values:
•"path_not_absolute"—the path indicated is not absolute;
•"file_not_found"—the file was not found;
•"file_not_regular"—the file is not a regular file;
•"file_not_block_device"—it is not a block device;
•"name_too_long"—the name is too long;
•"no_access"—access denied;
•"read_error"—reading error occurred;
•"write_error"—a writing error;
•"file_too_large"—the file is too large;
•"file_busy"—file is being used;
•"unpacking_error"— an unpacking error;
•"password_protected"—the archive is password protected;
•"arch_crc_error"—CRC archive error;
•"arch_invalid_header"—invalid archive header;
•"arch_no_memory"—not enough memory to unpack archive;
•"arch_incomplete"—incomplete archive;
•"can_not_be_cured"—file cannot be cured;
•"packer_level_limit"—packed object nesting level limit exceeded;
•"archive_level_limit"—archive nesting level limit exceeded;
•"mail_level_limit"—mail file nesting level limit exceeded;
•"container_level_limit"—container nesting level limit exceeded;
•"compression_limit"—compression rate limit exceeded;
•"report_size_limit"—report size limit exceeded;
•"scan_timeout"—scan timeout limit exceeded;
•"engine_crash"—scan engine failure;
•"engine_hangup"—scan engine hangup;
•"engine_error"—scan engine error;
•"no_license"—no active license found;
•"multiscan_too_late"—multiscanning error;
•"curing_limit_reached"—cure attempts limit exceeded;
•"non_supported_disk"—disk type is not supported;
•"unexpected_error"—an unexpected error. |
String
|
item
|
Report on the scanning of container attachments (if the object is a container, i.e. archive, attached MIME object, and so on)
|
Array of ScanReport tables
|
Overridden metamethods: None
|
The Archive table
The table describes archives and other compound objects.
Field
|
Description
|
Data type
|
type
|
Archive type:
•"archive"—archive;
•"mail"—email file;
•"container"—other container. |
String
|
name
|
Archive name, for example, ZIP
|
String
|
Overridden metamethods: None
|
Table DKIM
The table describes all DKIM signatures in the message.
Field
|
Description
|
Data type
|
signature
|
List of DKIM signatures present in the message
|
Array of DKIMSignature tables
|
has_valid_signature
|
A function that takes filter as an argument and returns
•the first found DKIM signature with the scan result that equals "pass" in the form of the DKIMSignature table;
•nil appears if no signatures failing verification have been detected.
As the filter argument, you can use:
•the DKIMSignatureFilter table;
•arbitrary predicate function, that receives the only DKIMSignature argument and returns a Boolean value
otrue—if the argument meets the condition;
ofalse—if the argument does not meet the condition. |
Function
|
Overridden metamethods: None
|
Table DKIMSignature
The table describes the properties of each DKIM signature in the message.
Field
|
Description
|
Data type
|
auid
|
The value Agent or User Identifier (AUID), obtained from the "i" tag of the DKIM signature, takes the default value into account
|
String
|
data
|
Text (base64) value of the signature extracted from the "b" tag of the DKIM signature
|
String
|
result
|
DKIM signature verification result
|
The DKIMResult table
|
sdid
|
The value Signing Domain Identifier (SDID), obtained from the "d" tag of the DKIM signature
|
String
|
selector
|
A selector, obtained from the "s" tag of the DKIM signature
|
String
|
Overridden metamethods: None
|
Table DKIMResult
The table describes the results of scanning for all DKIM signatures of the message.
Field
|
Description
|
Data type
|
type
|
DKIM signature verification result in the text format. It may have the following values:
•pass indicates that signature verification has been successful;
•fail indicates that signature verification has failed (i.e. it does not correspond with the hash of the email body or the signature could not be verified);
•neutral is a syntax error of the DKIM signature;
•temperror indicates a failed attempt at obtaining the domain key (DNS error);
•permerror indicates other types of errors (signature format, key format, inconsistencies between the key and the signature, and so on). |
String
|
comment
|
Comment on the scan result (can be used as a comment in Authentication-Results)
|
String
|
key_size
|
The key size used during the scan is either nil, or neutral if the attempt to obtain the key or the scan result has failed
|
Number
|
Overridden metamethods: None
|
Table DKIMSignatureFilter
The table describes the filter for DKIM message signatures (similar to the FileFilter table above). All fields are optional.
Field
|
Description
|
Data type
|
domain
|
A character set or a wildcard that the domain from the SDID field of the DKIM signature is expected to match
|
String or table of strings
|
domain_not
|
A character set or a wildcard that the domain from the SDID field of the DKIM signature is not expected to match
|
String or table of strings
|
Overridden metamethods: None
|
If the filter field is not specified (i.e. it contains the nil value), any DKIM signature of this message matches the filter. If several filter fields are specified, then the conditions are combined by conjunction (logical “AND”). If the filter field type is a table (array), then the filtered object must match at least one of the table (array) elements.
Table SPF
The table contains all the data necessary for checking SPF.
Field
|
Description
|
Data type
|
helo
|
The result of HELO check
|
Table SPFResult
|
from
|
The result of MAIL FROM check
|
Table SPFResult
|
check()
|
An auxiliary function; first performs the MAIL FROM check and then (if no verdict has been received)—the HELO check. The function returns the result of the check as a string that may have the same values as that of the status field in the SPFResult table.
The function is designed for transmitting the results to OpenDMARC via the generated Authentication-Results header
|
Function
|
Overridden metamethods: None
|
Table SPFResult
A table containing the result of checking SPF.
Field
|
Description
|
Data type
|
status
|
The result of the check represented as a string. It can have one of the following values (according to RFC 7208): none, neutral, pass, fail, softfail, temperror, permerror
|
String
|
explanation
|
The explanation of the result in case the fail response has been received.
|
String or nil if no explanation was received or it was impossible to get it
|
Overridden metamethods: None
|
Table VxcubeAnalysis
The table contains the result of object analysis in Dr.Web vxCube.
Field
|
Description
|
Data type
|
filename
|
The name of the analyzed attachment
|
String
|
id
|
Analysis ID
|
String
|
sample_id
|
Analyzed file ID
|
String
|
format_name
|
Analyzed file format
|
String
|
tasks
|
Analysis result
|
Array of VxcubeTask tables
|
max_maliciousness
|
Maximum value of the maliciousness field from the array of VxcubeTask tables. Can be a float from 0 to 100, or nil if there was an error.
|
Number or nil
|
Overridden metamethods: None
|
Table VxcubeTask
The table contains the result of object analysis performed on a certain platform in Dr.Web vxCube. The table structure is roughly equivalent to the TaskFinished object received via the Dr.Web vxCube API.
Field
|
Description
|
Data type
|
id
|
Task ID
|
String
|
status
|
Analysis status, such as "failed" or "finished"
|
String
|
platform_code
|
Code of the platform that the analysis was performed on. nil if there was an error.
|
String or nil
|
maliciousness
|
Maliciousness of the object. Can be a float from 0 to 100, or nil if there was an error.
|
Number or nil
|
verdict
|
Overall file maliciousness score corresponding to one of the three categories in the format of <category><degree>, where <category> is one of the following values: "neutral", "suspicious", "malware"; <degree> is an integer that represents the maliciousness degree (1 to 3). Examples of the verdict value: "malware1", "suspicious3".
|
String
|
Overridden metamethods: None
|
Available Auxiliary Modules
For interconnection with Dr.Web for UNIX Mail Servers in program space in Lua the following specific modules can be imported.
Name of the module
|
Function
|
drweb
|
Provides functions to record messages from the Lua program to the log of the Dr.Web for UNIX Mail Servers component which has launched the Lua program and the means of asynchronous execution of Lua procedures
|
drweb.lookup
|
Provides tools to request data from external sources by calling the Dr.Web LookupD module
|
drweb.dnsxl
|
Provides tools to check if the hosts’ addresses are in the DNSxL black lists
|
drweb.regex
|
Provides an interface to match strings and regular expressions
|
drweb.subprocess
|
Provides an interface to run external applications (processes)
|
drweb.config
|
Provides a table with the Dr.Web MailD configuration parameter values
|
drweb.store
|
Provides functions to store data between MailD runs
|
Contents of the drweb Module
1.Functions
The module provides a set of functions.
•Saving messages from the Lua program in the Dr.Web for UNIX Mail Servers component log:
▫log(<level>, <message>) writes the <message> string to the Dr.Web for UNIX Mail Servers log on the <level> level (the required level is defined using the “debug”, “info”, “notice”, “warning”, and “error”);
▫debug(<message>) writes the <message> string to the Dr.Web for UNIX Mail Servers log at the DEBUG level;
▫info(<message>) writes the <message> string to the Dr.Web for UNIX Mail Servers log at the INFO level;
▫notice(<message>) writes the <message> string to the Dr.Web for UNIX Mail Servers log at the NOTICE level;
▫warning(<message>) writes the <message> string to the Dr.Web for UNIX Mail Servers log at the WARNING level;
▫error(<message>) writes the <message> string to the Dr.Web for UNIX Mail Servers log at the ERROR level.
•Managing the synchronization of Lua procedures:
▫sleep(<sec.>) pauses the execution of a Lua procedure instance for a specified number of seconds.
▫async(<Lua function>[, <argument list>]) launches the specified function asynchronously and passes to it the specified argument list. The async function call completes immediately, and the return value (the table Future) allows you to obtain the result of the <Lua function>.
•Adding IP addresses to the IpAddress table:
▫ip(<address>) indicates an IP address, sent as the <address> string in the form of an IpAddress table. Either IPv4 or IPv6 addresses can be used.
•Uploading external data from a text file:
▫load_set(<file path>) generates a table with the true values from the contents of the specified text file; strings read from a file are used as keys. Empty strings as well as strings with blank spaces will be ignored;
▫load_array(<file path>) generates a string array from the contents of the specified text file. Empty strings and strings consisting of whitespace characters only, are ignored and are not included in the array.
2.Tables
•The Future table describes the pending result of performing a function using the async function.
Field
|
Description
|
Data type
|
wait
|
A function that returns the result of the function started using the async.function If the function has not completed its execution yet, it waits for the completion and returns the result. If the function is completed before wait is called, the result is returned immediately. If the started function fails, the wait call generates the same error.
|
Function
|
Overridden metamethods: None
|
•The IpAddress table describes an IP address.
Field
|
Description
|
Data type
|
belongs
|
Function checks an IP address stored in the IpAddress table for belonging to the specified subnets (IP address ranges).
Receives the only argument—a string that looks like: "<IP address>" or "<IP address>/<mask>", where <IP address>—a host address or a network address (for example, "127.0.0.1"), and <mask>—a subnetwork mask (can be specified as an IP address, for example, "255.0.0.0", or in the numerical form, for example, "8").
Returns a Boolean value:
•true indicates that the address equals to at least one of the specified addresses or belongs at least one of the specified subnets (range of IP addresses);
•false—otherwise. |
Function
|
Overridden metamethods:
•__tostring is a function that modifies IpAddress in a string, for example: "127.0.0.1" (IPv4) or "::1" (IPv6);
•__concat is a function that performs joining IpAddress to a string;
•__eq is a function that checks the equality of two IpAddress;
•__band—function that allows to apply a mask, for example: dw.ip('192.168.1.2') & dw.ip('255.255.254.0') |
3.Examples
•Writing the messages generated by a procedure initiating asynchronously to the log:
local dw = require "drweb"
-- This function waits two seconds and returns a string,
-- received as an argument
function out_msg(message)
dw.sleep(2)
return message
end
-- "Main" function
function intercept(ctx)
-- Output of a string at the NOTICE level to the Dr.Web for UNIX Mail Servers log
dw.notice("Intercept function started.")
-- An asynchronous start of two copies of the out_msg function
local f1 = dw.async(out_msg, "Hello,")
local f2 = dw.async(out_msg, " world!")
-- Waiting for the completion of the copies of the function
-- out_msg and output its results to log
-- the Dr.Web for UNIX Mail Servers log at the DEBUG level
dw.log("debug", f1.wait() .. f2.wait())
end
|
•Creating a scheduled procedure:
local dw = require "drweb"
-- Save the table Future in the future global variable in order
-- to preven the removal by the garbage collector
future = dw.async(function()
while true do
-- Everyday, the following message is displayed in the log
dw.sleep(60 * 60 * 24)
dw.notice("A brand new day began")
end
end)
|
•Modifying an IP address represented as a string into an IpAddress table::
local dw = require "drweb"
local ipv4 = dw.ip("127.0.0.1")
local ipv6 = dw.ip("::1")
local mapped = dw.ip("::ffff:127.0.0.1")
|
Contents of the drweb.lookup Module
1.Functions
The module provides the following functions:
•lookup(<request>, <parameters>) requests data from an external storage available via the Dr.Web LookupD module. The <request> argument must correspond to a section in the Dr.Web LookupD settings (the string <type>@<tag>). The <parameters> argument is optional. It describes substitutions that will be used to generate a request. The following automatically permitted markers can be used:
▫$u, $U is automatically replaced with user, the user name sent by the client component;
▫$d, $D is automatically replaced with domain, the domain sent by the client component.
These arguments are set as a table. Keys and values of this table must be strings. The function returns an array of strings that are results of the request;
•check(<checked string>, <request>, <parameters>) returns true if <checked string> is found in the external repository, available via the Dr.Web LookupD module. The arguments <request> and <parameters> are equivalent to the arguments of the lookup function (see above). The <checked string> argument is supposed to be a string or a table with the __tostring metamethod (i.e. that can be formatted into a string).
2.Examples
•Writing to the log list of users retrieved from the LookupD.LDAP.users data source:
local dw = require "drweb"
local dwl = require "drweb.lookup"
-- "Main" function
function intercept(ctx)
-- Writing the string at the NOTICE level to the Dr.Web for UNIX Mail Servers log
dw.notice("Intercept function started.")
-- Writing the request results to the Dr.Web for UNIX Mail Servers log
-- to the 'ldap@users' data source
for _, s in ipairs(dwl.lookup("ldap@users", {user="username"})) do
dw.notice("Result for request to 'ldap@users': " .. s)
end
end
|
Contents of the drweb.dnsxl Module
1.Functions
The module provides the following functions:
•ip(<IP address>, <DNSxL server>) requests DNS records of an A type from the DNSxL server <DNSxL server> that correspond to the specified IP address <IP address>.
If an IP address that is being checked is registered in the lists of the DNSxL server, then the result is a list of fictitious IP addresses. At that, each of the returned fictitious IP addresses can contain the reason for which the checked <IP address> is listed in the lists of this server (usually the reason type is determined by the value of the last octet of a returned fictitious IP address). If the DNSxL server does not contain the DNS records of an A type, for the IP address <IP address>, the function returns nil.
•url(<URL>, <SURBL server>) requests DNS records of an A type from the <SURBL server> server that correspond to the <URL> domain part (HTTP redirecting is not processed).
If the domain that is being checked, retrieved from <URL>, is registered in server lists of the SURBL server, then the result is a list of fictitious IP addresses. At that, each of the returned fictitious IP addresses can contain the reason for which the checked domain is listed in the lists of this server (usually the reason type is determined by the value of the last octet of a returned fictitious IP address). If the SURBL server does not contain the DNS records of an A type for domains from <URL>, the function returns nil.
Function arguments are strings or objects casted to strings (for example, as <IP address >, the IpAddress table can be used, and as <URL>—the Url table). IP addresses are returned as an array of the IpAddress tables.
2.Tables
•The IpAddress table describes the IP address. You can find the description of the table above.
3.Examples
•Output the results of the IP address scanning by the DNSxL server to the log:
local dw = require "drweb"
local dwxl = require "drweb.dnsxl"
-- "Main" function
function intercept(ctx)
-- Output of a string at the NOTICE level to the Dr.Web for UNIX Mail Servers log
dw.notice("Intercept function started.")
-- Output of the scanning results to the Dr.Web for UNIX Mail Servers log
-- 10.20.30.40 IP addresses are in the DNSxL server black list
-- dnsxl.server1.org
local records = dwxl.ip("10.20.30.40", "dnsxl.server1.org")
if records then
for _, ip in ipairs(records) do
dw.notice("DNSxL A record for 10.20.30.40: " .. ip)
end
end
end
|
Contents of the drweb.regex Module
1.Functions
The module provides the following functions:
•search(<template>, <text>[, <flags>]) returns true if the <text> string contains a substring that matches the <template> regular expression. The optional <flags> parameter (integer) is a set of flags affecting the function behavior connected with the logical OR.
•match(<template>, <text>[, <flags>])—the same as search except that the <template> regular expression must match the entire <text> string, not only its substring.
2.Available flags
•ignore_case ignores text case.
3.Examples
local rx = require "drweb.regex"
rx.search("te.?t", "some TexT") -- false
rx.search("te.?t", "some TexT", rx.ignore_case) -- true
rx.match("some.+", "some TexT") -- true
|
Contents of the drweb.subprocess Module
1.Functions
The module provides the function:
•run(<parameters >) runs the specified process (application) in the synchronous mode (the function gives control back only after the process exit). The <parameters> argument is a table that contains an executable path to the file, all arguments passing to the application at its launch (array argv), and optional parameters associated with the application input/output streams (stdin, stdout, stderr) that specify the working (current) directory of the application and environment variables.
The function result is a table that contains results of the process operation after its exit: exit code or signal number, at which the process was terminated. Moreover, returned table can contain fields with data that are read from the stdout and stderr output streams if they are specified in the table of the process running parameters.
2.Tables
•Table of input run parameters
Field
|
Description
|
Data type
|
(without name)
|
File path and application run arguments (array argv).
Required field. Field is repeated the number of the command-line arguments, the first value corresponds to argv[0], i.e. executable path.
|
String
|
stdin
|
Text that the application (process) will receive from the input stream (stdin) after its run. Optional field (if not specified, stdin will not receive anything).
|
String
|
stdout
|
Name of the field of the returned table. The field will receive the text that the process output to the stdout stream. Optional field (if not specified, the output will not be saved in stdout).
|
String
|
stderr
|
Name of the field of the returned table. The field will receive the text that the process output to the stderr stream. Optional field (if not specified, the output will not be saved in stderr).
|
String
|
env
|
Table whose fields are the environment variables that will be sent to the process environment. The environment variables are specified as pairs "<variable name>"="<value>". Optional field (if not specified, the environment variables are not set).
|
Table
|
workdir
|
Working (current) directory for the running process. Optional field (if not specified, the working directory is not set).
|
String
|
•Table of run results (the return value of the run function)
Field
|
Description
|
Data type
|
exit_status
|
Return code, with which the process exited successfully. Otherwise, it is nil.
|
Number
|
exit_signal
|
Signal number at which the process was terminated. Otherwise, it is nil.
|
Number
|
(value of the stdout field of the table of input parameters)
|
Data read from the stdout stream of an exited process. Field is available only if the stdout field is specified in the table of input parameters.
|
String
|
(value of the stderr field of the table of input parameters)
|
Data read from the stderr stream of an exited process. Field is available only if the stderr field is specified in the table of input parameters.
|
String
|
3.Examples
•To run the cat utility without arguments, to pass the 'some data' text to its input stream, and to pass the command output results to the stdout_field field of the returning table:
local sp = require 'drweb.subprocess'
local cat_result = sp.run({
'/bin/cat',
stdin = 'some data',
stdout = 'stdout_field',
})
|
Table of the result stored in the cat_result variable contains the following fields:
Field
|
Valueexit_status
|
exit_status
|
0
|
exit_signal
|
nil
|
stdout_field
|
'some data'
|
•To run the sh command (command interpreter) with the -с and env | grep TESTVAR 1>&2 parameters (command run by the interpreter), to add the TESTVAR variable with the VALUE value to the environment, and to pass the command stderr output result to the stderr_field field of the returning table:
local sp = require 'drweb.subprocess'
local env_result = sp.run({
'/bin/sh', '-c', 'env | grep TESTVAR 1>&2',
env = { TESTVAR = 'VALUE' },
stderr = 'stderr_field'
})
|
Table of the result stored in the env_result variable contains the following fields:
Field
|
Valueexit_status
|
exit_status
|
0
|
exit_signal
|
nil
|
stderr_field
|
'TESTVAR=VALUE\n'
|
•To run the pwd command and to set the working directory to the system root directory, and to pass the command stdout output results to the stdout_field field of the returning table:
local sp = require 'drweb.subprocess'
local pwd_result = sp.run{
'/bin/pwd',
workdir = '/',
stdout = 'stdout_field'
}
|
Table of the result stored in the pwd_result variable includes the following fields:
Field
|
Valueexit_status
|
exit_status
|
0
|
exit_signal
|
nil
|
stdout_field
|
'/\n'
|
•To run the kill command in bash and to pass the SIGKILL signal to the interpreter:
local sp = require 'drweb.subprocess'
local kill_result = sp.run{'/bin/bash', '-c', 'kill -9 $$'}
|
Table of the result stored in the kill_result variable includes the following fields:
Field
|
Valueexit_status
|
exit_status
|
nil
|
exit_signal
|
9
|
To run the process asynchronously, run the run function inside the async function call (see above).
Contents of the drweb.config Module
1.Functions
The module does not provide any functions.
2.Available tables
•The module provides the table MailDConfig with the following fields:
Field
|
Description
|
Data type
|
version
|
Dr.Web MailD version
|
String
|
Overridden metamethods: None
|
The MailDConfig table is provided by the module as the maild field.
3.Examples
•Output to log the current version of the Dr.Web MailD component:
local dw = require 'drweb'
local cfg = require 'drweb.config'
-- "Main" function
function milter_hook(ctx)
-- Output of a string at the NOTICE level to the Dr.Web for UNIX Mail Servers log
dw.notice(cfg.maild.version)
end
|
Contents of the drweb.store Module
1.Functions
The module provides the following functions:
•exists (<name>, <key>) checks if there is an entry with the specified key in the selected repository. Takes two arguments: <name> (string)—the name of the repository; <key> (string)—the key of the entry. Returns true if there is an entry, otherwise returns false;
•get (<name>, <key>) obtains the value of the entry with the specified key from the selected storage. Takes two arguments: <name> (string)—the name of the repository; <key> (string)—the key of the entry. Returns a pair with parameters: value, ctime; or nil if there is no entry. The value parameter (string)—the value of the entry with the specified key; ctime (integer)—record modification timestamp;
•put (<name>, <key>, <value>) adds an entry with the specified key to the selected storage. It takes three arguments: <name> (string)—the name of the repository; <key> (string)—the key of the entry, <value> (string)—the value of the entry;
•remove (<name>, <key>) removes the entry with the specified key from the selected storage. Takes two arguments: <name> (string)—the name of the repository; <key> (string)—the key of the entry;
•count (<name>) returns the number of records in the selected storage. Takes one argument: <name> (string)—the name of the repository. Returns an integer;
•drop (<name>, <ctime>) removes from the selected storage all entries that were modified before the specified timestamp. Takes two arguments: <name> (string)—the name of the repository; ctime (integer)—timestamp of the entry modification.
2.Examples
•Creating a white list for anti-spam scans:local store = require "drweb.store"
local store = require "drweb.store"
local antispam_whitelist = "antispam_whitelist"
local intra_domain_mask = ".*@test%.test$"
-- "Main" function
function milter_hook(ctx)
-- Add all the outgoing mails recipients
-- to the anti-spam white list
if ctx.from:match(intra_domain_mask) then
for _, to in ipairs(ctx.to) do
store.put(antispam_whitelist, to, "")
end
return {action="accept"}
end
if not store.exists(antispam_whitelist, ctx.from) then
if ctx.message.spam.score > 300 then
return {action="reject"}
end
end
return {action="accept"}
end
|
•Temporary addition to the white list:
local store = require "drweb.store"
local antispam_whitelist = "antispam_whitelist"
local antispam_whitelist_timeout = 604800 -- 1 week
local intra_domain_mask = ".*@test%.test$"
-- "Main" function
function milter_hook(ctx)
-- Add all the outgoing mails recipients
-- to the anti-spam white list
if ctx.from:match(intra_domain_mask) then
for _, to in ipairs(ctx.to) do
store.put(antispam_whitelist, to, "")
end
return {action="accept"}
end
local _, ctime = store.get(antispam_whitelist, ctx.from)
-- Is on the list and was added within a week
local in_whitelist = ctime and os.time() + ctime < antispam_whitelist_timeout
if not in_whitelist and ctime then
store.remove(antispam_whitelist, ctx.from)
end
-- You can also update a non-expired entry:
-- if in_whitelist then
-- store.put(antispam_whitelist, ctx.from, "")
-- end
if not in_whitelist then
if ctx.message.spam.score > 300 then
return {action="reject"}
end
end
return {action="accept"}
end
|
|