In this section
•General Information
•Script for Milter
▪Requirements for the Script
▪Examples
▪Tables in Use (MilterContext, MilterSender, MilterResult, MilterModifications, MilterAddedField, MilterChangedField, MilterGenerator, MilterModifier)
•Script for Spamd
▪Requirements for the Script
▪Tables in Use (SpamdContext, SpamdReportResult)
•Script for Rspamd
▪Requirements for the Script
▪Example
▪Tables in Use (RspamdContext, RspamdSender, RspamdResult, RspamdSymbol)
•Script for SMTP
▪Requirements for the Script
▪Example
▪Tables in Use (SmtpContext, SmtpResult)
•Tables Describing the Message Structure:
▪RcptTo,
▪MimeMessage,
▪MimePart,
▪From,
▪To,
▪ContentType,
▪ContentDisposition,
▪Spam,
▪Virus,
▪Url,
▪RawUrl,
▪ThreatFilter (with examples),
▪UrlFilter (with examples),
▪FileFilter (with an example),
▪PartFilter (with examples),
▪ScanReportFilter (with examples),
▪MimeHeader,
▪HeaderField,
▪HeaderFieldValue,
▪MimeBody,
▪ScanReport,
▪Archive,
▪DKIM,
▪DKIMSignature,
▪DKIMResult,
▪DKIMSignatureFilter,
▪SPF,
▪SPFResult,
▪VxcubeAnalysis,
▪VxcubeTask
•Available Auxiliary Modules:
▪drweb,
▪drweb.lookup,
▪drweb.dnsxl,
▪drweb.regex,
▪drweb.subprocess,
▪drweb.config,
▪drweb.store
General Information
The Dr.Web MailD component supports interaction via the Lua program interpreter (version 5.3.4 is used; it is bundled with Dr.Web for UNIX Mail Servers). Scripts written in Lua can be used by the component to analyze and process email messages.
A message received via Milter, Spamd, Rspamd, or in the SMTP mode is analyzed using a Lua script specified in the settings of Dr.Web MailD as the value of the MilterHook, SpamdHook, RspamdHook or Smtphook parameter respectively. The value of this parameters can be either the full code of the script or a 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 calls this function to process all received messages). The processing function must comply with 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 potential actions to be applied to the message if it is accepted.
An example below illustrates a function which always returns to Dr.Web MailD the Accept verdict for all messages received for scanning via the Milter interface (here and elsewhere 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 to the X-Found header values;
•adds the [SPAM] prefix to a message subject (the Subject header value) if the spam score exceeds 100 points;
•sends the message to the recipient after it is processed.
function milter_hook (ctx)
-- Add names of detected threats to the header
for threat in ctx.message.threats() do
ctx.modifier.add_header_field("X-Found", threat.name)
end
-- Change the Subject header value, if the message spam score exceeds 100 points
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 the message to the recipient having applied the pending changes
return {
action = "accept",
modifications = ctx.modifier.modifications()
}
end
|
2.Placing detected threats and the message itself (if its spam score is exceeded) in a protected archive
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 = ""
-- Place all message parts where threats were found
-- in 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 message if its spam score
-- exceeds 100 points
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 the message to the recipient having applied the pending changes
-- Note that if the modification table is not specified,
-- it will be returned automatically
return {action = "accept"}
end
|
The message being scanned will be modified: all unwanted parts will be removed, archived and added to an attachment.
The archive in which the unwanted elements of the message are enclosed is protected with the password specified as the value of the ctx.modifier.repack_password variable. The password specified in the RepackPassword parameter in the configuration file is not used in this case.
Tables in Use
MilterContext Table
This table is used as an input argument of the milter_hook function. It contains the information about the message being processed (fields, structure, headers, body, information about a sender and recipients, 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 message sender.
|
MilterSender Table
|
helo
|
The welcome HELO/EHLO string received from the SMTP client that sent the 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
|
Email addresses of recipients (without angle brackets).
An example of a hook to process messages having multiple recipients:
if re.match("(eve|neil)@(example\\.com)$", ctx.from or '', re.ignore_case) and ctx.to.all_match("(tom|kane)@example\\.com$")
then
dw.notice("no_checking")
else
dw.notice("do something")
end
|
|
RcptTo Table
|
message
|
Email message (with the body and all headers)
|
MimeMessage Table
|
modifier
|
The MilterModifier table that contains all changes to be applied to the message if the "accept" action is generated according to the scanning results in the MilterResult table.
|
MilterModifier Table
|
gen
|
The MilterGenerator table used for generating custom headers, such as X-Antivirus
|
MilterGenerator Table
|
spf
|
The SPF table used for performing an SPF check of the sender
|
SPF Table
|
Overridden metamethods: None
|
MilterSender Table
This table is used as the sender field of the MilterContext table. Contains the information about the message 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 absent or unknown (not provided by the MTA)
|
IpAddress Table
|
Overridden metamethods: None
|
MilterResult Table
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
|
Text of a response 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 changes to be applied to the message before sending it to the recipient.
Optional field. Only used if action = "accept".
|
MilterModifications Table
|
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 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 content 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 reported value of incident_text is not empty. |
String or boolean value
|
Overridden metamethods: None
|
MilterModifications Table
The table is used for description of all changes to be made to the message in case of delivering it to the recipient (the accept action is chosen). All fields of the table are optional; if a corresponding field does not have a value, the action specified in this field is not applied to the message.
Field
|
Description
|
Data type
|
new_body
|
New message body (without headers) 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
|
MilterAddedField Table
The table contains the description of the headers to be added to the message.
Field
|
Description
|
Data type
|
name
|
Header name
|
String
|
value
|
Header value
|
String
|
Overridden metamethods: None
|
MilterChangedField Table
The table contains the description of the headers to be modified in the message (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 custom table received from the context.
|
MilterGenerator Table
The table contains auxiliary methods for generating 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 about the anti-virus components involved in the scanning of the message. The HeaderField table or nil (if the message has not been scanned yet) is returned.
The name field in the HeaderField table has a fixed value (X-Antivirus).
|
Function
|
authentication_results_header_field
|
The function is used for generating the Authentication-Results header which contains the information about the results of DKIM and SPF checks. Takes the authserv_id optional argument (a string) which is the ID of the authenticang server in the generated header. By default the authserv_id value 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 table has a fixed value (Authentication-Results).
|
Function
|
Overridden metamethods: None
|
MilterModifier Table
The table is used for describing changes to be made in the message after it is processed (if it is sent to the recipient).
Field
|
Description
|
Data type
|
add_header_field
|
Function which schedules an action to add a new header to the message.
Receives two mandatory arguments:
•name is a name of the header to be added in the form of a string;
•value is the header value in the form of a string.
The value is encoded in accordance with RFC 2047.
|
Function
|
change_header_field
|
Function that schedules an action to change (or remove) the specified header.
Receives two mandatory arguments:
•name is a name of the header to be changed in the form of a string;
•value is the header value in the form of 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 is removed from the message.
The value is encoded in accordance with RFC 2047.
|
Function
|
modifications
|
Function that returns the MilterModifications table containing the entire list of changes scheduled to be made in the message. Does not accept any arguments.
|
Function
|
repack
|
Function that schedules the repacking of the specified message part (or the entire message, if the part is not specified or the specified part does not exist). During repacking, the specified parts are added to a password-protected archive.
Accepts the path or iterator optional argument:
•path is a path to the scanned attachment to be archived. If the path is not specified or the specified path is invalid, the entire 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 provided by the returned iterator are scheduled for repacking.
If the function argument is not specified or the specified path is invalid, the entire message is archived.
Examples:
-- Schedule packing to a password-protected archive:
-- the entire message
ctx.modifier.repack()
-- Schedule all message parts that contain executables
-- a message part at the specified path (or
-- the entire message if the part does not exist)
ctx.modifier.repack('/1/2/3')
-- Schedule all message parts that contain executables
-- all parts that contain executables
ctx.modifier.repack(ctx.message.files{name='*.exe'})
-- Schedule moving to a password-protected archive
-- all attachments that are .zip archives
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. The default value is "quarantine.zip".
|
String
|
repack_password
|
Password for the archive protection. If it is not specified, the password specified in the configuration file is used (the RepackPassword parameter).
|
String
|
repack_message
|
Arbitrary message about the reasons for repacking the message (or its parts). It is added to the final message (can be absent).
|
String
|
templates_dir
|
Path to a directory where a repacking template is stored. The path is relative referring to the path specified in the configuration file (the TemplatesDir parameter). The default value is "milter" (that is, templates from the milter subdirectory are used).
|
String
|
cure
|
Function that schedules curing an attachment.
Accepts the path or iterator optional argument:
•path is a path to an attachment of the message being scanned. 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 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. The function returns true if all 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 path or iterator optional argument:
•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 incurable attachments to be repacked.
Identical to calling cure_or_repack(ctx.message.leaf_parts()) if the function argument is not specified. The function returns true if all attachments are harmless or have been cured. If at least one attachment cannot be cured, the function returns false and schedules all incurable attachments 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 a password-protected archive
ctx.modifier.repack()
-- Return a verdict via the milter protocol (MilterResult) table)
-- 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 fields, that is the MilterModifications tables) directly, without using the MilterModifier table:
-- Enable message sending to recipients by adding
-- the "X-Checked: True" header to them
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 in 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 calls this function to process all received messages). The processing function must comply with 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 message);
3.The only return value is the completed SpamdReportResult table. The return value defines the response via the Spamd protocol.
An example below illustrates a function which returns the verdict to Dr.Web MailD on whether the message should be marked as spam (spam score: 200, minimum score for classifying as spam: 100, message: The message was recognized as spam; here and elsewhere the ctx argument is an instance of the SpamdContext table):
-- A trivial example
function spamd_report_hook(ctx)
return {
score = 200,
threshold = 100,
report = "The message was recognized as spam"
}
end
|
Tables in Use
SpamdContext Table
The table is used as an input argument of the spamd_report_hook function. It contains the information about the message being processed (fields, structure, headers, body, information about the sender and recipients, 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
|
MimeMessage Table
|
Overridden metamethods: None
|
SpamdReportResult Table
The table represents the result returned by the spamd_report_hook function. The results of scanning for spam are passed to Dr.Web MailD and sent by MTA.
Field
|
Description
|
Data type
|
score
|
Spam score assigned to the message during scanning (the $spam_score and $spam_score_int variables are expanded for Exim)
|
Number
|
threshold
|
Threshold point at which the message is classified as spam
|
Number
|
report
|
Text result of the message scanning (the $spam_report variable is expanded for Exim)
|
String
|
incident
|
Description of the incident in the registered event of the Mail type.
•If the field is a string, the content 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 reported 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 that is an entry point in the message scanning module (Dr.Web MailD calls this function to process all received messages). The processing function must comply with 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 message being processed; 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 the RspamD protocol.
An example of the correct definition of the script (here and elsewhere the ctx argument is an instance of the RspamdContext table):
-- A trivial example
function rspamd_hook(ctx)
return {
score = 200,
threshold = 100
}
end
|
Example
The script below returns the recommended actions for the MTA as well as the RspamdSymbol table 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 anti-spam library",
score = 80
}
}
}
end
|
Tables in Use
RspamdContext Table
The table is used as an input argument of the rspamd_hook function and contains the following information about the 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
|
RspamdSender Table
|
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
|
Email address of the sender (without angle brackets, for example: "user@domain.com") or nil if the address is absent or unknown (not provided by the MTA)
|
String
|
to
|
Email addresses of recipients without angle brackets
|
RcptTo Table
|
message
|
Email message
|
MimeMessage Table
|
spf
|
The SPF table used for performing an SPF check of the sender
|
SPF Table
|
Overridden metamethods: None
|
RspamdSender Table
The table contains the information about the message sender.
Field
|
Description
|
Data type
|
hostname
|
Name (FQDN) of the sender’s host, or nil if the name is absent or unknown (not provided by the MTA)
|
String
|
ip
|
IP address of the sender’s host, or nil if the IP address is absent or unknown (not provided by the MTA)
|
IpAddress Table
|
Overridden metamethods: None
|
RspamdResult Table
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 (the $spam_score and $spam_score_int variables are expanded for Exim)
|
Number
|
threshold
|
Minimum spam score for the message to be classified as spam
|
Number
|
action
|
Optional field. Action recommended for the MTA as a result of the message scanning (the $spam_action variable is expanded for Exim)
|
String
|
symbols
|
Optional field. Array of RspamdSymbol tables for adding points specified in the score field to the spam score
|
Array of RspamdSymbol tables
|
incident
|
Description of the incident in the registered event of the Mail type.
•If the field is a string, the content 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 reported value of incident_text is not empty. |
String or boolean value
|
Overridden metamethods: None
|
RspamdSymbol Table
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 calls this function to process all received messages). The processing function must comply with 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 a password-protected archive
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 in Use
SmtpContext Table
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 message sender.
|
MilterSender Table
|
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
|
Email addresses of recipients without angle brackets
|
RcptTo Table
|
message
|
Email message
|
MimeMessage Table
|
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.
|
MilterModifier Table
|
gen
|
The MilterGenerator table used for generating custom headers, such as X-Antivirus
|
MilterGenerator Table
|
spf
|
The SPF table used for performing an SPF check of the sender
|
SPF Table
|
Overridden metamethods: None
|
SmtpResult Table
The result returned by the smtp_hook function. Contains the descriptions of actions to be applied to the message being scanned.
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 changes to be applied to the message before sending it to the recipient.
Optional field. Only used if action = "accept".
|
MilterModifications Table
|
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 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 content 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 reported value of incident_text is not empty. |
String or boolean value
|
Overridden metamethods: None
|
Tables Describing the Message Structure
RcptTo Table
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
|
MimeMessage Table
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
|
Spam Table
|
from
|
The From header value, or nil if From is absent in the message
|
From Table
|
to
|
The To header value, or nil if To is absent in the message
|
To Table
|
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 operating 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
|
MimePart Table
The table describes a part of the email message:
Field
|
Description
|
Data type
|
header
|
Header of the message
|
MimeHeader Table
|
body
|
Body of the part, or nil if there are attached parts.
|
MimeBody Table
|
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.
|
ContentDisposition Table
|
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.
|
ContentType Table
|
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. The function returns an attached message part (table MimePart) that is located at the specified path.
path is a string that looks like "/1/2/3" and expands as 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 (any) has been found in the 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
-- a link to "adult_content" or "social_networks" 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
-- a link to "example.com" with respect to host has been found
end
if ctx.message.has_url{host_not = "*example.com"} then
-- a link has been 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 with a port number more than 80 has been found
end
|
|
Function
|
has_threat
|
Function that takes filter as an optional argument (see the 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 filter condition;
•false—if this part of the message or its attached parts do not contain a threat that meets the filter condition.
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 the 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 filter condition (including files in archives);
•false—if this part of the message and its attached parts do not contain a URL that meets the filter condition (including files in archives).
Examples:
if ctx.message.has_file() then
-- at least one file has been found in the message
end
if ctx.message.has_file{name = "*.exe"} then
-- at least one exe file has been found in the message
end
|
|
Function
|
has_part
|
Function that takes filter as an optional argument (see the 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 the 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
|
From Table
A table describing the From 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 and the string. |
To Table
The table describes the To message header. Contains the same fields and methods as the From table.
ContentType Table
The table describes the Content-Type header of 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 the name of a parameter (string);
•value is the value of a parameter (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 and the string. |
ContentDisposition Table
The table describes the Content-Disposition header of 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 the name of a parameter (string);
•value is the value of a parameter (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 and the string. |
Spam Table
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"—a 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 score 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
|
The anti-spam library version
|
String
|
Overridden metamethods: None
|
Virus Table
The table describes a threat.
Field
|
Description
|
Data type
|
type
|
Threat type (according to the Doctor Web classification). Possible values:
•"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
|
Url Table
Table that describes URLs found in the message.
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
|
raw
|
A raw, undecoded URL
|
RawUrl Table
|
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 a URL to the owner’s website; otherwise, it is nil.
|
String
|
in_categories
|
The function that accepts the categories mandatory argument—the URL category list (a string or an array of strings). The function returns a boolean value:
•true—if the URL belongs to at least one of the specified categories;
•false—if the URL does not belong to any of the categories. |
Function
|
Overridden metamethods:
•__tostring—the function returns the Url content as a string (in the UTF-8 encoding);
•__concat—the function concatenates the URL string value and another string. |
RawUrl Table
The table contains the undecoded URL data.
Field
|
Description
|
Data type
|
scheme
|
Scheme (protocol) prefix, for example, "http". If the prefix is absent, the value is nil.
|
String
|
host
|
Host name or IP address, for example, "example.com". If it is absent, the value is nil.
|
String
|
port
|
Port number, for example, 80. If it is absent, the value is nil.
|
Number
|
path
|
Path to a resource, for example, "index.html". If it is absent, the value is nil.
|
String
|
Overridden metamethods:
•__tostring—the function returns the RawUrl content as a string (in the UTF-8 encoding);
•__concat—the function concatenates the RawUrl string value and another string. |
ThreatFilter Table
The table describes a filter for threats. All fields are optional.
Field
|
Description
|
Data type
|
category
|
List of categories that the threat must 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 cannot 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
|
UrlFilter Table
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
|
The list of categories that the URL may not 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
|
FileFilter Table
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 names of the parts that contain files with the .exe extension.
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
|
PartFilter Table
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 may be an empty string if
-- it is not specified in Content-Type and 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 the images in the message by their type:
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
|
ScanReportFilter Table
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
|
MimeHeader Table
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
|
HeaderField Table
The table describes the message part header.
Field
|
Description
|
Data type
|
name
|
Header name
|
String
|
value
|
Header value
|
HeaderFieldValue Table
|
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
|
HeaderFieldValue Table
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. |
MimeBody Table
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
|
ScanReport Table
|
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 operating in SMTP mode.
|
Array of VxcubeAnalysis tables
|
Overridden metamethods: None
|
ScanReport Table
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"—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
|
Reports on the scanning of embedded items if the scanned object is a container (an archive, attached MIME object, and so on)
|
Array of ScanReport tables
|
Overridden metamethods: None
|
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
|
DKIM Table
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
|
DKIMSignature Table
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
|
DKIMResult Table
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
|
DKIMSignatureFilter Table
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.
SPF Table
Contains all data necessary for checking SPF.
Field
|
Description
|
Data type
|
helo
|
The result of HELO check
|
SPFResult Table
|
from
|
The result of MAIL FROM check
|
SPFResult Table
|
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
|
SPFResult Table
Contains 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 (in accordance with 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
|
VxcubeAnalysis Table
The table contains the result of analyzing the object 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
|
VxcubeTask Table
Contains the result of object analysis performed on a separate platform in Dr.Web vxCube. The table structure is roughly equivalent to the TaskFinished object received using 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.
•Storing 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 one of the following values (string): debug, info, notice, warning, 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 Future table) allows you to obtain the result of the <Lua function>.
•Storing the information about an IP address in the form of the IpAddress table:
▫ip(<address>) indicates an IP address sent as the <address> string in the form of the 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 a specified text file; strings read from the file are used as keys. Empty strings and strings with white spaces will be ignored;
▫load_array(<path to file>) generates a string array from the contents of a specified text file. Empty strings and strings consisting only of white spaces are ignored.
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 its 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 specified subnets (IP address ranges).
Accepts a single 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 matches at least one of the specified IP addresses or belongs to at least one of the specified subnets (the range of IP addresses);
•false—if the address does not match any one of the specified addresses or does not belong to any of the specified subnets |
Function
|
Overridden metamethods:
•__tostring is a function that transforms IpAddress into a string, for example, 127.0.0.1 (IPv4) or ::1 (IPv6);
•__concat is a function that joins IpAddress to a string;
•__eq is a function that checks the equality of two IpAddress;
•__band is a function that allows to apply a mask, for example: dw.ip('192.168.1.2') & dw.ip('255.255.254.0') |
3.Examples
•Logging messages generated by a procedure initiated asynchronously:
local dw = require "drweb"
-- This function returns a string received as an argument
-- after the delay of two seconds
function out_msg(message)
dw.sleep(2)
return message
end
-- "Main" function
function intercept(ctx)
-- Output the string at the notice level to the log of Dr.Web for UNIX Mail Servers
dw.notice("Intercept function started.")
-- Run two instances of the out_msg function asynchronously
local f1 = dw.async(out_msg, "Hello,")
local f2 = dw.async(out_msg, " world!")
-- Wait for the completion of the instances of the function
-- out_msg and log their results
-- Dr.Web for UNIX Mail Servers at the debug level
dw.log("debug", f1.wait() .. f2.wait())
end
|
•Creating a scheduled procedure:
local dw = require "drweb"
-- Store the Future table as a futurе global variable to
-- prevent its removal by the garbage collector
future = dw.async(function()
while true do
-- Log the following message each day
dw.sleep(60 * 60 * 24)
dw.notice("A brand new day began")
end
end)
|
•Transform the string to the IP address:
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 <type>@<tag>string). The <parameters> argument is optional and describes substitutions to 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 name sent by the client component.
Arguments are set as a table, which keys and values 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 <request> and <parameters> arguments are equivalent to the arguments of the lookup function (see above). The <checked string> argument must be a string or a table with a __tostring metamethod (i.e. that can be transformed into a string).
2.Examples
•Log a 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)
-- Store the string in the Dr.Web for UNIX Mail Servers log at the notice level
dw.notice("Intercept function started.")
-- Store in the Dr.Web for UNIX Mail Servers log results of requesting
-- the 'ldap@users' data source
for _, s in ipairs(dwl.lookup("ldap@users", {user="username"})) do
dw.notice("Result of 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 the string at the NOTICE level to the Dr.Web for UNIX Mail Servers log
dw.notice("Intercept function started.")
-- Output to the Dr.Web for UNIX Mail Servers log the scanning results of
-- 10.20.30.40 IP address from 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 which 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 the 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 all entries that were modified before the specified timestamp from the selected storage. 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 recipients of outgoing messages
-- 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 recipients of outgoing messages
-- 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 the 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
|
|