Email Processing in Lua

In this section

General Information

Script for Milter

Script for Spamd

Script for Rspamd

Script for SMTP

Tables Describing the Message Structure

Available Auxiliary Modules

General Information

The Dr.Web MailD component supports interaction via the Lua program interpreter (version 5.3.4 is used; it is supplied together with Dr.Web for UNIX Mail Servers). Scripts written in Lua can be used by the component for the analyzing and processing of email messages.

Email messages received via Milter, Spamd, Rspamd, or in the SMTP mode are analyzed with the help of a Lua script specified in the settings of Dr.Web MailD as the value of the MilterHook, SpamdHook, RspamdHook or Smtphook parameter respectively. You can specify the value of these parameters either as the full text of the script or as the path to it.

More examples of Lua scripts for processing emails are available at:
https://github.com/DoctorWebLtd/drweb-lua-examples/tree/master/maild.

Script for Message Processing for the Milter Interface

Requirements for the Script

The script must contain a global function, that is an entry point in the message scanning module (Dr.Web MailD will call this function for processing all incoming messages). The processing function should match the following call conventions:

1.Function name is milter_hook;

2.The only argument is the MilterContext table (provides access from the function to the information about the processed email message);

3.The only returned value is the MilterResult completed table. The returned value defines a verdict about the scanned message: accept, reject, change, or discard, as well as actions to be applied (possibly) to the message if it is accepted.

Below you can see an example of a correctly defined function that always returns to Dr.Web MailD the accept verdict for all messages received for scanning via the Milter interface (here and after the ctx argument is an instance of the MilterContext table):

function milter_hook(ctx)
  return {action = "accept"}
end

Examples

1.Detecting threats and checking for signs of spam

The script below performs the following operations:

adds names of threats detected in an email message as values of the header X-Found;

adds the [SPAM] prefix to the email subject (the value of the header Subject) if the spam score exceeds 100 points;

sends the message to the recipient after it is processed.

function milter_hook (ctx)

 -- Add the detected threats’ names to the header
 for threat in ctx.message.threats() do
   ctx.modifier.add_header_field("X-Found", threat.name)
 end

 -- Change the value of the Subject header, if a message has more than 100 points of spam scoring
 if ctx.message.spam.score > 100 then
   local old_value = ctx.message.header.value("Subject") or ""
   local new_value = "[SPAM] " .. old_value
   ctx.modifier.change_header_field("Subject", new_value)
 end

 -- Send a message to a recipient, applying the pending changes
 return {
   action = "accept",
   modifications = ctx.modifier.modifications()
 }

end

2.Placing all detected threats in a protected archive and archiving the message (if the spam score is exceeded)

The script below performs the following operations:

places the detected threats in a protected archive;

places an email message in a protected archive if the spam score exceeds 100 points.

function milter_hook(ctx)

 ctx.modifier.repack_password = "xxx"
 ctx.modifier.repack_message = ""

 -- Move all message parts where threats were found
 -- to a password protected archive
 for threat, path in ctx.message.threats() do
   ctx.modifier.repack(path)
   local msg = " Threat found: " .. threat.name
   ctx.modifier.repack_message = ctx.modifier.repack_message .. msg
 end

 -- Repack the whole email message if it has
 -- more than 100 points of spam scoring
 if ctx.message.spam.score > 100 then
   ctx.modifier.repack()
   local msg = " Spam score: " .. ctx.message.spam.score
   ctx.modifier.repack_message = ctx.modifier.repack_message .. msg
 end

 -- Send a message to a recipient, applying the pending changes
 -- Note that if the modification table is not specified,
 -- it will be automatically returned
 return {action = "accept"}

end

The message being checked will be modified: all the unwanted parts will be removed, archived and sent to the recipient as an attachment.
The archive in which the unwanted elements of the message will be enclosed will be protected with the password specified as the value of the ctx.modifier.repack_password variable. Note that the password specified in the RepackPassword parameter in the configuration file will not be valid in this case.

Tables Used in Scripts

Table MilterContext

This table is used as an input argument of the milter_hook function. It contains the information about the email message being processed (fields, structure, headers, body, information about the sender and the recipient, information about the SMTP session).

Field

Description

Data type

session_id

Identifier of the client session during which messages from this client are processed.

String

sender

Information about the sender of the email message.

Table MilterSender

helo

The welcome HELO/EHLO string received from the SMTP client that had sent the email message, or nil if the string is missing/unknown (not provided by the MTA)

String

from

Sender’s email address without angle brackets (for example: user@domain.com)

String

to

Recipients’ email addresses without angle brackets

Table RcptTo

message

Email message (with the body and all headers)

Table MimeMessage

modifier

The MilterModifier table that contains all changes to be applied to a message if the "accept" action is generated according to the scanning results in the MilterResult table.

Table MilterModifier

gen

The MilterGenerator table used for generating special headers, such as X-Antivirus

Table MilterGenerator

spf

The SPF table used for performing SPF checks of the sender

Table SPF

Overridden metamethods: None

Table MilterSender

This table is used as the sender field of the MilterContext table. It contains the information about the email sender.

Field

Description

Data type

hostname

Sender’s host name (FQDN)

String

family

Connection type as a string

"U"—unknown type

"L"—connection via a UNIX socket

“4”—connection via IPv4

"6"—connection via IPv6

String

port

Port number

Integer

ip

IP address of the sender's host, or nil if the IP address is missing or unknown (not provided by the MTA)

Table IpAddress

Overridden metamethods: None

Table MilterResult

The table represents the result returned by the milter_hook function.

Field

Description

Data type

action

String with description of the action that should be applied to the message:

"accept"—accept (i.e. allow MTA to send the message to the recipient);

"discard"—discard the message without notifying the sender

"reject"—reject the message and return the SMTP 5** code to the sender;

"tempfail"—reject the message and return the SMTP 4** code to the sender;

"replycode"—send the SMTP response, that is specified in the code field, to the sender.

Required field.

String

code

A three-digit SMTP response code to be sent to the sender, for example, "541".

Optional field. Only used if action = "replycode".

String

text

String with a response text sent to the sender, for example, "User not local or invalid address – Relay denied".

Optional field. Only used if action = "replycode".

String

message

String with a response text sent to the sender, for example, "Message rejected as spam".

Optional field. Only used if action = "reject".

String

modifications

Table describing the changes to be applied to the email message before sending it to the recipient.

Optional field. Only used if action = "accept".

Table MilterModifications

added_recipients

List of email addresses of additional message recipients.

Optional field. Only used if action = "accept".

String array

deleted_recipients

List of email addresses to be excluded from the list of the message recipients.

Optional field. Only used if action = "accept".

String array

incident

Description of the incident in the registered event of the Mail type.

If the field is a string, the contents of this string will be transmitted to the incident_text field of the Mail event and the event will be registered;

If the field is boolean and is equal to false, then the incident_text field of the Mail event will be absent and the event will not be registered;

If the field is boolean and is equal to true, then the incident_text field of the Mail event will be filled in automatically and the event will be registered, if the value of incident_text is not empty.

String or boolean value

Overridden metamethods: None

Table MilterModifications

The table is used for description of all changes to be made to the email message once the decision to deliver it to a recipient has been taken (the accept action has been selected). All fields of the table are optional; if a field value is missing, the action specified in this field is not applied to the message:

Field

Description

Data type

new_body

New message body (without headers) which should be used to replace the body of the message being processed.

String

added_fields

Headers to be added to the message being processed.

Array of MilterAddedField tables

changed_fields

Headers to be modified or removed from the message being processed.

Array of MilterChangedField tables

Overridden metamethods: None

Table MilterAddedField

The table contains the description of headers to be added to the message being processed.

Field

Description

Data type

name

Header name

String

value

Header value

String

Overridden metamethods: None

Table MilterChangedField

The table contains the description of the headers to be modified in the message being processed (or removed from it).

Field

Description

Data type

name

Header name

String

index

Ordinal number of the header with the name name in the message to be changed (counting from 1)

Number

value

New value of the header (or an empty string "" to remove the header).

String

Overridden metamethods: None

For description of the changes to be made to the message after processing, it is recommended not to fill in the MilterModifications table directly. You should use methods from the MilterModifier table instead that can be received from the context.

Table MilterGenerator

The table contains secondary methods for generating the X-Antivirus and X-Authentication-Results standard headers.

Field

Description

Data type

х_antivirus_header_field

The function is used for generating the X-Antivirus header that contains the information upon the anti-virus components involved in the scanning of the message and returns the HeaderField table or nil (if the message has not been scanned yet).
The name field in the HeaderField has the fixed value (X-Antivirus).

Function

authentication_results_header_field

The function is used for generating the Authentication-Results header which contains the information upon the results of DKIM and SPF checks. It takes as an optional argument the authserv_id string which is the ID of the server in the generated header. By default the value of authserv_id matches the name of the host on which Dr.Web MailD is running.
The function returns the HeaderField table.
The name field in the HeaderField has the fixed value (Authentication-Results).

Function

Overridden metamethods: None

Table MilterModifier

The table is used for scheduling changes to the message after it is processed (if it is sent to the recipient).

Field

Description

Data type

add_header_field

Function that schedules an action to add a new header to the email message.

Receives two mandatory arguments:

name is the header name as a string;

value is the header value as a string.

The value will be encoded according to RFC 2047.

Function

change_header_field

Function that schedules an action to change (or remove) the specified header.

Receives two mandatory arguments:

name is the header name as a string;

value is the header value as a string.

If the message has multiple headers with the specified name, the function will change the value of the first header with such name. In case of multiple value changes of the same header, only the last value is kept. If the value is an empty string "", the header name will be removed from the message.

The value will be encoded according to RFC 2047.

Function

modifications

Function that returns the MilterModifications table containing the whole list of changes scheduled to be made to the email message. Does not have any arguments.

Function

repack

Function that schedules the repacking of the specified message part (or the whole message, if a part is not specified or the specified part does not exist). During the repacking, the specified parts will be added to archive with a password.

Accepts the optional argument path or iterator:

path is a path to the scanned email attachment to be archived. If the path is not specified or if the specified path is not valid, the whole message is archived.

iterator is a message part iterator, returned by the functions threats, urls, attachments, files, parts, leaf_parts, and text_parts of the MimePart table. In this case, all parts of the message returned by the iterator will be scheduled for repacking.

If the function argument is not specified or if the specified path is not valid, the whole message is archived.

Examples:

-- Schedule the entire message to be repacked
-- to an archive with a password
ctx.modifier.repack()

-- Schedule some parts of a message at the specified path
-- (or the entire message if the part does not exist)
-- to be repacked to an archive with a password
ctx.modifier.repack('/1/2/3')

-- Schedule all message parts that contain executables
-- to be repacked to an archive with a password
ctx.modifier.repack(ctx.message.files{name='*.exe'})

-- Schedule all ZIP attachements to be repacked
-- to an archive with a password
ctx.modifier.repack(ctx.message.attachments{name='*.zip'})

Function

repack_archive_name

Name of the archive for packing malicious or unwanted items of the message. By default, "quarantine.zip".

String

repack_password

Password for the archive protection. If it is not specified, the password specified in the configuration file is used (RepackPassword parameter).

String

repack_message

Arbitrary message about the reasons of the message (or its parts) repacking. It is added to the final message (can be absent).

String

templates_dir

Path to a directory, where the repacking template is stored. The path is relative referring to a path specified in the configuration file (TemplatesDir parameter). The default value is "milter" (that is, templates from the milter subdirectory will be used).

String

cure

Function that schedules the curing of an attachment.

Accepts the optional argument path or iterator:

path is the path to the scanned email attachment. The cure(path) function returns true if the attachment is harmless or has been cured. If the attachment cannot be cured, the function returns false.

iterator is a message part iterator returned by the functions threats, urls, attachments, files, parts, leaf_parts, and text_parts of the MimePart table. In this case, all parts of the message returned by the iterator will be scheduled for curing. The cure(iterator) function returns true if all the attachments are harmless or have been cured. If at least one attachment cannot be cured, the function returns false.

Identical to calling cure(ctx.message.leaf_parts()) if the function argument is not specified. Returns true if all the attachments are harmless or have been cured. If at least one attachment cannot be cured, the function returns false.

Function

cure_or_repack

Function that schedules the curing of an attachment. If it cannot be cured, the attachment is repacked. During the repacking, the specified parts will be added to an archive with a password.

Accepts the optional argument path or iterator:

path is the path to the scanned email attachment. The cure_or_repack(path) function returns true if the attachment is harmless or has been cured. If the attachment cannot be cured, the function returns false and schedules the attachment to be repacked.

iterator is a message part iterator returned by the functions threats, urls, attachments, files, parts, leaf_parts, and text_parts of the MimePart table. In this case, all parts of the message returned by the iterator will be scheduled for curing. The cure_or_repack(iterator) function returns true if all the attachments are harmless or have been cured. If at least one attachment cannot be cured, the function returns false and schedules all the incurable attachment to be repacked.

Identical to calling cure_or_repack(ctx.message.leaf_parts()) if the function argument is not specified. Returns true if all the attachments are harmless or have been cured. If at least one attachment cannot be cured, the function returns false and schedules all the incurable attachment to be repacked.

Function

Overridden metamethods: None

To access this table, you should use the modifier field of the MilterContext table. For example:

function milter_hook(ctx)

 -- Schedule adding a new header
 -- at the end of the list of headers
 ctx.modifier.add_header_field("X-Name", "Value")

 -- Schedule changing the "Subject" field value to "New value"
 ctx.modifier.change_header_field("Subject", "New value")

 -- Schedule repacking messages to an archive with a password
 ctx.modifier.repack()

 -- Return verdict via the milter protocol (table MilterResult)
 -- and apply all pending changes of the message
 return {action = "accept"}
end

In the example below you can see how to fill in the MilterResult table (and its modifications field, that is the MilterModifications table) directly, without using the MilterModifier table:

-- Enable message sending to recipients by adding
-- the "X-Checked: True" header

function milter_hook(ctx)
 return {
  action = "accept",
  modifications = {
    added_fields = {
      {
        name = "X-Checked",
        value = "True"
      }
    }
  }
 }
end

The next example shows how to return the accept verdict despite the changes made to the MilterModifier table:

function milter_hook(ctx)

 …

 -- Schedule adding the message header
 ctx.modifier.add_header_field('X-Header', 'some value')

 …

 -- Force return of an empty MilterModifications table
 return {action = "accept", modifications = {}}
end

Script for Message Processing for the Spamd Interface

Requirements for the Script

The script must contain a global function, that is an entry point in the message scanning module (Dr.Web MailD will call this function for processing all incoming messages). The processing function should match the following call conventions:

1.Function name is spamd_report_hook;

2.The only argument is the SpamdContext table (provides access from the function to the information about the processed email message);

3.The only return value is the completed SpamdReportResult table. The return value defines the response via Spamd.

Below you can see an example of a correct definition of the function which always returns to Dr.Web MailD the verdict that the message must be marked as spam (spam score: 200, minimum score for classifying as spam: 100, message: The message was recognized as spam; here and after the ctx argument is an instance of the SpamdContext table):

-- An example of a trivial realization

function spamd_report_hook(ctx)
 return {
  score = 200,
  threshold = 100,
  report = "The message was recognized as spam"
 }
end

Tables Used in Lua Scripts

Table SpamdContext

The table is used as an input argument of the spamd_report_hook function. It contains the information about the email message being processed (structure, headers, body, information about the sender and the recipient, information about the SMTP session).

Field

Description

Data type

session_id

Identifier of the client session during which messages from this client are processed.

String

message

Email message

Table MimeMessage

Overridden metamethods: None

Table SpamdReportResult

The table represents the result returned by the spamd_report_hook function. It passes the results of scanning for spam to Dr.Web MailD, the results should be returned to MTA.

Field

Description

Data type

score

Spam rating assigned to the message (for the Exim MTA fills the $spam_score and $spam_score_int variables)

Number

threshold

Threshold point at which a message is classified spam

Number

report

Text result of the message scanning (for the Exim MTA fills the $spam_report variable)

String

incident

Description of the incident in the registered event of the Mail type.

If the field is a string, the contents of this string will be transmitted to the incident_text field of the Mail event and the event will be registered;

If the field is boolean and is equal to false, then the incident_text field of the Mail event will be absent and the event will not be registered;

If the field is boolean and is equal to true, then the incident_text field of the Mail event will be filled in automatically and the event will be registered, if the value of incident_text is not empty.

String or boolean value

Overridden metamethods: None

Script for Message Processing for the Rspamd Interface

Requirements for the Script

The script must contain a global function serving as an entry point for the message scanning module (Dr.Web MailD will call this function for processing a newly received message). The processing function should match the following call conventions:

1.Function name is rspamd_hook;

2.The only argument is the RspamdContext table (provides access from the function to the information about the processed email message; see the table description below);

3.The only return value is the completed RspamdResult table (see the table description below). The return value defines the response via RspamD.

An example of the correct definition of the script (here and after the ctx argument is an instance of the RspamdContext table):

-- An example of a trivial realization

function rspamd_hook(ctx)
 return {
  score = 200,
  threshold = 100
 }
end

Example

The script below returns the recommended actions for MTA as well as the RspamdSymbol containing the spam score with a brief comment (signs of spam detected in the message and the number of points corresponding to each sign):

function rspamd_hook(ctx)
 return {
  score = 1080,
  threshold = 100,
  action = "REJECT:Malicious message"
  symbols = {
   {
     name = "Threat found",
     score = 1000
   },
   {
     name = "Spam score by the third-party anti-spam library",
     score = 80
   }
  }
 }
end

Tables Used in Lua Scripts

Table RspamdContext

The table is used as an input argument of the rspamd_hook function. It contains the information about the email message being processed.

Field

Description

Data type

session_id

Identifier of the client session during which messages from this client are processed.

String

sender

Information about the message sender

Table RspamdSender

helo

The HELO/EHLO string received from the SMTP client, or nil if the string is missing/unknown (not provided by the MTA)

String

from

Sender’s email address (without angle brackets, for example: user@domain.com) or nil if the address is missing/unknown (not provided by the MTA)

String

to

Recipients’ email addresses without angle brackets

Table RcptTo

message

Email message

Table MimeMessage

spf

The SPF table used for performing SPF checks of the sender

Table SPF

Overridden metamethods: None

Table RspamdSender

The table contains the information about the message sender.

Field

Description

Data type

hostname

Name (FQDN) of the sender's host, or nil if missing or unknown (not provided by the MTA)

String

ip

IP address of the sender's host, or nil if missing or unknown (not provided by the MTA)

Table IpAddress

Overridden metamethods: None

Table RspamdResult

The table represents the result returned by the rspamd_hook function. Contains the message scanning report.

Field

Description

Data type

score

Spam score assigned to the message after scanning (for the Exim MTA fills the $spam_score and $spam_score_int variables)

Number

threshold

Minimum spam score above which the message is treated as spam

Number

action

Optional field. Action recommended for MTA as a result of the message scanning (for the Exim MTA fills the $spam_action variable)

String

symbols

Optional field. Array of RspamdSymbol tables for determining the reason of assigning the number of spam points specified in the score field

Array of RspamdSymbol tables

incident

Description of the incident in the registered event of the Mail type.

If the field is a string, the contents of this string will be transmitted to the incident_text field of the Mail event and the event will be registered;

If the field is boolean and is equal to false, then the incident_text field of the Mail event will be absent and the event will not be registered;

If the field is boolean and is equal to true, then the incident_text field of the Mail event will be filled in automatically and the event will be registered, if the value of incident_text is not empty.

String or boolean value

Overridden metamethods: None

Table RspamdSymbol

The table describes the signs of spam detected in the message (for example, file with a threat, unwanted URL, and so on) for which points have been added to the spam score.

Field

Description

Data type

name

Name of the detected sign of spam

String

score

Number of points added to the spam score upon detection of this sign

Number

description

A brief description of the detected sign of spam (optional field)

String

Overridden metamethods: None

Script for Message Processing in SMTP Mode

Requirements for the Script

The script must contain a global function that is an entry point in the message scanning module (Dr.Web MailD will call this function for processing newly received message). The processing function should match the following call conventions:

1.Function name is smtp_hook;

2.The only argument is the SmtpContext table (provides access from the function to the information about the processed email message);

3.The only returned value is the SmtpResult completed table. The returned value defines a verdict about the scanned message: accept, reject, change, or discard, as well as actions to be applied (possibly) to the message if it is accepted.

Below you can see an example of a correctly defined function that always returns to Dr.Web MailD the Accept verdict for all messages received for scanning via SMTP mode (here and after the ctx argument is an instance of the SmtpContext table):

function smtp_hook(ctx)
 return {action = "accept"}
end

Example

The script below returns the Accept verdict for all email messages to Dr.Web MailD and adds the "X-Checked: True" header field to all messages:

function smtp_hook(ctx)
 return {
  action = "accept",
  modifications = {
   added_fields = {
     {
      name = "X-Checked",
      value = "True"
     }
   }
  }
 }
end

In order to form the modifications table, you can use the auxiliary MilterModifier object of the SmtpContext table, for example:

function smtp_hook(ctx)
 local modifier = ctx.modifier

 -- Schedule appending a new field to the end of the header
 modifier.add_header_field("X-Name", "Value")

 -- Schedule changing the "Subject" field value to "New value"
 modifier.change_header_field("Subject", "New value")

 -- Schedule repacking messages to an archive with a password
 modifier.repack()

 -- Apply all pending changes to the message and send it
 -- modifications do not have to be specified, the changes will be taken directly from modifier
 return { action = "accept", modifications = modifier.modifications() }
end

Tables Used in Scripts

Table SmtpContext

The table is used as an input argument of the smtp_hook function. It contains the information about the email message being processed.

Field

Description

Data type

session_id

Identifier of the client session during which messages from this client are processed.

String

sender

Information about the sender of the email message.

Table MilterSender

helo

The HELO/EHLO string received from the SMTP client, or nil if the string is missing/unknown (not provided by the MTA)

String

from

Sender’s address (without angle brackets, for example: "user@domain.com")

String

to

Recipients’ email addresses without angle brackets

Table RcptTo

message

Email message

Table MimeMessage

modifier

The MilterModifier table contains all changes to be made to a message if the "accept" action is generated according to the scanning results in the MilterResult table.

Table MilterModifier

gen

The MilterGenerator table used for generating special headers, such as X-Antivirus

Table MilterGenerator

spf

The SPF table used for performing SPF checks of the sender

Table SPF

Overridden metamethods: None

Table SmtpResult

The table represents the result returned by the smtp_hook function. It contains the descriptions of actions to be applied to the message being checked.

Field

Description

Data type

action

String with description of the action that should be applied to the message:

"accept"—accept (i.e. allow MTA to send the message to the recipient);

"discard"—discard the message without notifying the sender;

"tempfail"—reject the message and return the SMTP 4** code to the sender.

Required field.

String

modifications

Table describing the changes to be applied to the email message before sending it to the recipient.

Optional field. Only used if action = "accept".

Table MilterModifications

added_recipients

List of email addresses of additional message recipients.

Optional field. Only used if action = "accept".

String array

deleted_recipients

List of email addresses to be excluded from the list of the message recipients.

Optional field. Only used if action = "accept".

String array

message

String with a response text sent to the sender about the message being rejected. Is returned to the sender with the 541 code is the message is being checked synchronously.

Optional field. Only used if action = "reject".

String

incident

Description of the incident in the registered event of the Mail type.

If the field is a string, the contents of this string will be transmitted to the incident_text field of the Mail event and the event will be registered;

If the field is boolean and is equal to false, then the incident_text field of the Mail event will be absent and the event will not be registered;

If the field is boolean and is equal to true, then the incident_text field of the Mail event will be filled in automatically and the event will be registered, if the value of incident_text is not empty.

String or boolean value

Overridden metamethods: None

Tables Describing the Message Structure

Table RcptTo

The table contains an array of email addresses of the message recipients (without angle brackets) that encountered in the RCPT TO command of the SMTP protocol as well as the following additional information:

Field

Description

Data type

search

The function that checks for the presence of at least one address corresponding to at least one of the specified templates in the address array.

Accepts one mandatory patterns argument, i.e. search patterns, i.e. one (string) or several (array of strings) regular expressions in the Perl syntax (PCRE).

Returns a Boolean value:

true—if an address corresponding to at least one template has been found;

false—if no address corresponding to at least one template has been found.

Not case-sensitive.

Function

all_match

The function that checks whether all addresses correspond to at least one of the specified templates in the address array.

Accepts one mandatory patterns argument, i.e. search patterns, i.e. one (string) or several (array of strings) regular expressions in the Perl syntax (PCRE).

Returns a Boolean value:

true—all addresses fully correspond to at least one template;

false—no address fully corresponds to any of the templates

Not case-sensitive.

Function

Overridden metamethods: None

Table MimeMessage

The table describes the email message being processed as a whole (includes the same fields as the MimePart table and some additional information)

Field

Description

Data type

dkim

DKIM signatures (see RFC 6376) of the email message

The DKIM table

raw

Email message received from the client

String

spam

Report about the results of the message scanning for spam signs

Table Spam

from

The From header value, or nil if From is absent in the message

Table From

to

The To header value, or nil if To is absent in the message

Table To

date

The Date header value, or nil if Date is absent in the message

String

message_id

The Message-ID header value, or nil if Message-ID is absent in the message

String

subject

The Subject header value, or nil if Subject is absent in the message

String

user_agent

The User-Agent header value, or nil if User-Agent is absent in the message

String

vxcube_analysis

Message analysis result from Dr.Web vxCube. The field is present only when in SMTP mode.

Array of VxcubeAnalysis tables

(the next fields are similar to those of the MimePart table; they describe the root MIME part)

Overridden metamethods: None

Table MimePart

The table describes a part of the email message:

Field

Description

Data type

header

Header of the message

Table MimeHeader

body

Body of the part, or nil if there are attached parts.

Table MimeBody

part

Attached (to the current message part) parts as an array of tables. If there are no attached parts, the array is empty.

Array of MimePart tables

content_disposition

Contents of the Content-Disposition header, or nil, if this header is absent in the part.

Table ContentDisposition

content_id

Contents of the Content-ID header, or nil, if this header is absent in the part.

String

content_type

Contents of the Content-Type header, or nil, if this header is absent in the part.

Table ContentType

name

Attachment name, or nil if the part is not an attachment

String

part_at

Function that receives the path argument—the path to a child part of the message. Returns an attached message part (table MimePart) that is located at the specified path.

Path is a string that looks like "/1/2/3", that is root_part. part [1]. part [2]. part [3]. Paths that look like "", "/", "//", and so on (without numbers) correspond to the message part that this function is called from (i.e. root_part). If there is no child part at the specified path, as well as when the path is incorrect, the function returns nil.

Function

threats

Function that takes filter as an optional argument. The function returns a single value—an iterator function. Using this iterator, it is possible to go through all threats that are located in this part of the message and in its attached parts and that meet the specified filter condition. The iterator function does not have any arguments and returns two values:

the Virus table;

relative path to the message part that contains the detected threat.

As the filter argument, you can use:

the ThreatFilter table;

arbitrary predicate function that receives the only Virus argument and returns a Boolean value:

otrue—if the argument meets the condition (being a threat);

ofalse—if the argument does not meet the condition (being a threat)

Function

urls

Function that takes filter as an optional argument. The function returns a single value—an iterator function. Using this iterator, it is possible to go through all URLs that are located in this part of the message and in its attached parts and that meet the specified filter condition. The iterator function does not have any arguments and returns two values:

the Url table;

relative path to the message part that contains the found URL.

As the filter argument, you can use:

the UrlFilter table;

arbitrary predicate function that receives the only Url argument and returns a Boolean value:

otrue—if the argument meets the condition (is unwanted);

ofalse—if the argument does not meet the condition (is not unwanted)

Function

attachments

Function that takes filter as an optional argument. The function returns a single value—an iterator function. Using this iterator, it is possible to go through all attachments that are located in this part of the message and in its attached parts and that meet the specified filter condition. The iterator function does not have any arguments and returns two values:

the MimePart table;

relative path to the message part that contains the found attachment.

As the filter argument, you can use:

the PartFilter table;

arbitrary predicate function that receives the only MimePart argument and returns a Boolean value:

otrue—if the argument meets the condition;

ofalse—if the argument does not meet the condition

Function

files

Function that takes filter as an optional argument. The function returns a single value—an iterator function. Using this iterator, it is possible to go through all files that are located in this part of the message and in its attached parts (including archives) and that meet the specified filter condition. The iterator function does not have any arguments and returns two values:

file name as a string;

relative path to the message part that contains the found file.

As the filter argument, you can use:

the FileFilter table;

arbitrary predicate function that receives a file name as a string and returns a Boolean value:

otrue—if the argument meets the condition;

ofalse—if the argument does not meet the condition

Function

parts

Function that takes filter as an optional argument. The function returns a single value—an iterator function. Using this iterator, it is possible to go through all message parts that are located in this part of the message and in its attached parts and that meet the specified filter condition. The iterator function does not have any arguments and returns two values:

the MimePart table;

relative path to the message part.

As the filter argument, you can use:

the PartFilter table;

arbitrary predicate function that receives the MimePart table and returns a Boolean value:

otrue—if the argument meets the condition;

ofalse—if the argument does not meet the condition

Function

leaf_parts

Function that takes filter as an optional argument. The function returns a single value—an iterator function. Using this iterator, it is possible to go through all leaf parts that are located in this part of the message and in its attached parts and that meet the specified filter condition. The iterator function does not have any arguments and returns two values:

the MimePart table;

relative path to the message part.

As the filter argument, you can use:

the PartFilter table;

arbitrary predicate function that receives the MimePart table and returns a Boolean value:

otrue—if the argument meets the condition;

ofalse—if the argument does not meet the condition.

Function

text_parts

Function that takes filter as an optional argument. The function returns a single value—an iterator function. Using this iterator, it is possible to go through all text parts that are located in this part of the message and in its attached parts and that meet the specified filter condition. The iterator function does not have any arguments and returns two values:

the MimePart table;

relative path to the message part.

As the filter argument, you can use:

the PartFilter table;

arbitrary predicate function that receives the MimePart table and returns a Boolean value:

otrue—if the argument meets the condition;

ofalse—if the argument does not meet the condition.

Function

scan_reports

Function that takes filter as an optional argument. The function returns a single value—an iterator function. Using this iterator, it is possible to go through all reports of scanning this part of the message and its attached parts, that meet the specified filter condition.

The iterator function does not have any arguments and returns single value: the ScanReport table.

As the filter argument, you can use:

the ScanReportFilter table;

arbitrary predicate function that receives the ScanReport table and returns a Boolean value:

otrue—if the argument meets the condition;

ofalse—if the argument does not meet the condition.

Function

has_url

Function that takes filter as an optional argument. (see description of the urls function above).

Returns a Boolean value:

true—if this part of the message and its attached parts contain a URL that meets the condition filter;

false—if neither the part of the message nor the attached parts contain a URL that meets the condition filter.

Examples:

if ctx.message.has_url() then
  -- at least one URL has been found in the email message
end

if ctx.message.has_url{category = "adult_content"} then
  -- an adult content link has been found
end

if ctx.message.has_url{category = {"adult_content", "social_networks"}} then
  -- an "adult_content" or a "social_networks" link has been found
end

if ctx.message.has_url{category = "black_list"} then
  -- a link to a blacklisted resource been found
end

if ctx.message.has_url{host = "example.com"} then
  end
end

if ctx.message.has_url{host_not = "*example.com"} then
  -- a link detected with a host that does not correspond to the "*example.com" template
end

if ctx.message.has_url(function(url) return port > 80 end) then
  -- a link whose port number is more than 80 has been found
end

Function

has_threat

Function that takes filter as an optional argument.(see description of the threats function above).

Returns a Boolean value:

true—if this part of the message and its attached parts contain a threat that meets the condition filter;

false—if neither the part of the message nor the attached parts contain a threat that meets the condition filter.

Examples:

if ctx.message.has_threat() then
  -- the message contains at least one threat of any category
end

if ctx.message.has_threat({category = "known_virus"}) then
  -- the message contains at least one threat of the "known_virus" category
end

if ctx.message.has_threat{category = "known_virus"} then
  -- the same
end

if ctx.message.has_threat({category = {"known_virus", "joke"}}) then
  -- the message contains at least one threat of the "known_virus" or "joke" category
end

if ctx.message.has_threat{category_not = "joke"} then
  -- the message contains a threat of any category except "joke"
end

Function

has_file

Function that takes filter as an optional argument. (see description of the files function above).

Returns a Boolean value:

true—if this part of the message and its attached parts contain a file that meets the condition filter (including files in archives);

false—if neither the part of the message nor the attached parts contain a URL that meets the condition filter.

Examples:

if ctx.message.has_file() then
  -- at least one file has been found in the email message
end

if ctx.message.has_file{name = "*.exe"} then
  -- at least one exe file has been found in the email message
end

Function

has_part

Function that takes filter as an optional argument. (see description of the parts function above).

Returns a Boolean value:

true—if this part of the message and its attached parts contain a part that meets the condition filter;

false—if neither the part of the message nor the attached parts contain a part that meets the condition filter.

Function

has_scan_report

Function that takes filter as an optional argument. (see description of the scan_reports function above).

Returns a Boolean value:

true—if this part of the message and its attached parts contain a scan report that meets the condition filter;

false—if neither the part of the message nor the attached parts contain a scan report that meets the condition filter.

For usage examples, see the description of the ScanReportFilter table.

Function

search

Function that searches for text in this message section using a regular expression (PCRE). Receives a regular expression (string). Note that if you use strings in the quotation marks, the slash character must be escaped.

Returns a Boolean value:

true—if a match with the specified regular expression has been found in this section or in a child part;

false—if a match with the specified regular expression has not been found in this section or in a child part

Function

Overridden metamethods: None

Table From

A table describing the From email message header. It contains the list of email addresses extracted from the header (array of strings) and the following additional information.

Field

Description

Data type

search

The function that checks for the presence of at least one address corresponding to at least one of the specified templates in the address array.

Accepts one mandatory patterns argument, i.e. search patterns, i.e. one (string) or several (array of strings) regular expressions in the Perl syntax (PCRE).

Returns a Boolean value:

true—an address that fully corresponds to at least one template has been found;

false—no address that fully corresponds to at least one template has been found.

Not case-sensitive.

Function

all_match

The function that checks whether all addresses correspond to at least one of the specified templates in the address array.

Accepts one mandatory patterns argument, i.e. search patterns, i.e. one (string) or several (array of strings) regular expressions in the Perl syntax (PCRE).

Returns a Boolean value:

true—all addresses fully correspond to at least one template;

false—no address fully corresponds to at least one template.

Not case-sensitive.

Function

Overridden metamethods:

__tostring is the function that returns the decoded header value;

__concat is the function that concatenates the decrypted value of the header with a string.

Table To

The table describes the To email message header. It contains the same fields and methods as the From table.

Table ContentType

The table describes the Content-Type header in the message part.

Field

Description

Data type

type

MIME type of the message part

String

subtype

Subtype of the message part

String

param

Header parameters in the form of a table array with the following fields:

name is a parameter name (string);

value is parameter value (string).

Table array

Overridden metamethods:

__tostring is the function that returns the decoded header value;

__concat is the function that concatenates the decrypted value of the header with a string.

Table ContentDisposition

The table describes the Content-Disposition header in the message part.

Field

Description

Data type

type

View type of the message part

String

param

Header parameters in the form of a table array with the following fields:

name is a parameter name (string);

value is parameter value (string).

Table array

Overridden metamethods:

__tostring is the function that returns the decoded header value;

__concat is the function that concatenates the decrypted value of the header with a string.

Table Spam

Table contains the spam check report for the specified message.

Field

Description

Data type

type

Message type (spam status). Possible values:

"legit"—the message is not spam;

"spam"—the message is spam;

"virus"—the third-party heuristic analyzer has detected a virus in the message body;

"bounce"—the message contains a report on a negative delivery (DSN) sent to the sender of the original message;

"suspicious"—a suspicious message;

"pce"—a “professional” commercial (advertising) message, send by a valid subscription service;

"mce"—a commercial (advertising) message, not sent by valid subscription services, but with a way to unsubscribe;

"dce"—“dirty” commercial (advertising) message with no way of unsubscribing;

"community"—a message from a social network;

"transactional"—a transaction-related message (registration, purchase of services or goods);

"phishing"—a fraudulent message;

"scam"—a fraudulent message (a scam message).

String

score

Spam rating assigned to the message

Number

normalized_score

Number of spam points score normalized in the interval [0, 1)

Number

reason

Encrypted string that contains an explanation why the email message is spam

String

version

Third-party anti-spam library version

String

Overridden metamethods: None

Table Virus

The table describes a threat.

Field

Description

Data type

type

Threat type (according to the Doctor Web classification):

"known_virus"—a known threat (a threat that has a description in the virus databases);

"virus_modification"—a modification of the known threat;

"unknown_virus"—an unknown threat, suspicious object;

"adware"—an advertising program;

"dialer"—a dialer program;

"joke"—a joke program;

"riskware"—a potentially dangerous program;

"hacktool"—a hacktool.

String

name

Threat type (according to the Doctor Web classification)

String

Overridden metamethods: None

Table Url

Table that describes an URL.

Field

Description

Data type

scheme

Scheme (protocol) prefix, for example, "http"

String

host

Host name or IP address, for example, "example.com"

String

port

Port number, for example, 80. If it is absent in the URL, the value is nil.

Number

path

Path to a resource, for example, "index.html". If it is absent in the URL, the value is nil.

String

categories

Array of categories to which the URL is placed based on the result of scanning. Possible values:

"infection_source"—an infection source;

"not_recommended"—a source that is not recommended for visiting;

"adult_content"—adult content;

"violence"—violence;

"weapons"—weapons;

"gambling"—gambling;

"drugs"—drugs;

"obscene_language"—obscene language;

"chats"—chats;

"terrorism"—terrorism;

"free_email"—free email;

"social_networks"—social networks;

"owners_notice"—websites added due to a notice from copyright owner;

"online_games"—online games;

"anonymizers"—anonymizers;

"cryptocurrency_mining_pools"—cryptocurrency mining pools;

"jobs" — job search sites;

"black_list"—black list (resources considered non-recommended by the mail server administrator).

Table of strings

legal_url

If the URL belongs to the owners_notice category, the field contains the URL to the owner’s website; otherwise, it is nil.

String

Overridden metamethods:

__toString—the function returns the Url content as a string (in the UTF-8);

__concat—the function concatenates the URL string value and another string.

Table ThreatFilter

The table describes a filter for threats. All fields are optional.

Field

Description

Data type

category

List of categories that the threat is expected to match (not case-sensitive). See the list of categories in description of the type field of the Virus table.

String or table of strings

category_not

List of categories that the threat is not expected to match (not case-sensitive).

String or table of strings

Overridden metamethods: None

If the filter field is not specified (the value is nil), any threat matches the filter. If several filter fields are specified, then the condition is combined by a conjunction (logical AND). If the filter field is a table (list), the object must match at least one of the table (list) items.

Usage examples:

1.Write to the log all the names of the threats detected in the message:

function milter_hook(ctx)

 …

 for virus in ctx.message.threats() do
  dw.notice("threat found: " .. virus.name)
 end

 …

end

2.Write to the log the names the of threats that match the category filter, and the names of the message parts where the threats have been detected:

function milter_hook(ctx)

 …

 for v, p in ctx.message.threats({category = "known_virus"}) do
  dw.notice("found " .. v.name .. " in " .. ctx.message.part_at(p).name(p))
 end

 …

end

3.Write to the log the threat names that match the predicate function, and the names of the message parts where the threats have been detected:

function milter_hook(ctx)

 …

 local function eicar_filter(v)
  return v.name == "EICAR Test File (NOT a Virus!)"
 end

 for v, p in ctx.message.threats(eicar_filter) do
  dw.notice("found " .. v.name .. " in " .. ctx.message.part_at(p).name(p))
 end

 …

end

Table UrlFilter

The table describes the filter applied to URLs (similar to the table ThreatFilter above); all its fields are optional:

Field

Description

Data type

category

List of categories that the URL must match (not case-sensitive). See the list of categories in description of the categories field of the Url table.

String or table of strings

category_not

List of categories that the URL cannot match (not case-sensitive).

String or table of strings

text

Text that must match the URL

String or table of strings

text_not

Text that cannot match the URL

String or table of strings

host

Host (domain) that must be present in the URL

String or table of strings

host_not

Host (domain) that cannot be present in the URL

String or table of strings

Overridden metamethods: None

If the filter field is not specified (the value is nil), any threat matches the filter. If several filter fields are specified, then the condition is combined by a conjunction (logical AND). If the filter field is a table (list), the object must match at least one of the table (list) items.

Usage examples:

1.Write to the log all the URLs found in the message:

function milter_hook(ctx)

 …

 for url in ctx.message.urls() do
  dw.notice("url found: " .. url)
 end

 …

end

2.Write to the log the URLs that match the category, and names of the message parts where the URLs have been found:

function milter_hook(ctx)

 …

 for u, p in ctx.message.urls{category = "adult_content"} do
  dw.notice("found " .. u.text .. " in " .. ctx.message.part_at(p).name(p))
 end

 …

end

Table FileFilter

The table describes the filter applied to files (similar to the table ThreatFilter above). All fields are optional.

Field

Description

Data type

name

A character set or a wildcard that the name of the file is expected to match. For example: "*.exe", "eicar.txt".

Not case-sensitive.

String or table of strings

name_re

A regular expression (PCRE) that the file name is expected to match. For example: ".*\\.zip", [[.*\.zip]].

Not case-sensitive. Note that if you use strings in the quotation marks, the slash character must be escaped.

String or table of strings

name_not

A character set or a wildcard that the name of the file is not expected to match.

Not case-sensitive.

String or table of strings

name_re_not

A regular expression (PCRE) that the file name is expected to match.

Not case-sensitive. Note that if you use strings in the quotation marks, the slash character must be escaped.

String or table of strings

Overridden metamethods: None

If several filter fields are specified, the condition is combined by conjunction (logical AND). If the filter field is a table (array), the object must match at least one of the table (array) items. If the filter field is not specified (the value is nil), any file matches the filter.

Usage example:

Output to the log the the names of the parts that contain files with an extension .exe.

function milter_hook(ctx)

 …

 for f, p in ctx.message.files{name = "*.exe"} do
  local where = ctx.message.part_at(p).name
  if not where or where == "" then where = p end
  dw.notice("EXE found in " .. where)
 end

 …

end

Table PartFilter

The table describes the filter for message parts (similar to the table FileFilter above); all its fields are optional.

Field

Description

Data type

name

A character set or a wild card that the name of the part is expected to match. For example: "*.exe", "eicar.txt".

Not case-sensitive.

String or table of strings

name_re

A regular expression (PCRE) that the name of the part is expected to match. For example: ".*\\.zip", [[.*\.zip]].

Not case-sensitive. Note that if you use strings in the quotation marks, the slash character must be escaped.

String or table of strings

content_type

A character set that the Content-Type value of the part is expected to match. For example: "image/*".

Not case-sensitive.

String or table of strings

content_disposition

A character set that the Content-Disposition value of the part (attachment) is expected to match. For example: "inline", "attachment".

Not case-sensitive.

String or table of strings

name_not

A character set that the name of the file is not expected to match.

Not case-sensitive.

String or table of strings

name_re_not

A regular expression (PCRE) that the name of the part is not expected to match.

Not case-sensitive. Note that if you use strings in the quotation marks, the slash character must be escaped.

String or table of strings

content_type_not

A character set that the Content-Type value of the part is not expected to match.

Not case-sensitive.

String or table of strings

content_disposition_not

A character set that the Content-Disposition value of the part is not expect to match.

Not case-sensitive.

String or table of strings

Overridden metamethods: None

If the filter field is not specified (the value is nil), any part (attachment) matches the filter. If several filter fields are specified, then the condition is combined by a conjunction (logical AND). If the filter field is a table (array), the object must match at least one of the table (array) items.

Usage examples:

1.Write to the log all the attachments and their MD5 hashes:

function milter_hook(ctx)

 …

 for a, p in ctx.message.attachments() do
  -- the attachment name be an empty string
  -- if it is not specified in Content-Type and in Content-Disposition
  local name = a.name
  if name == "" then name = "at path " .. p end
  dw.notice("Attachment: " .. name .. "; md5=" .. a.body.md5)
 end

 …

end

2.Write to the log all the attachments with an .exe extension:

function milter_hook(ctx)

 …

 for a in ctx.message.attachments{name = "*.exe"} do
  dw.notice("EXE attachment: " .. a.name)
 end

 …

end

3.Count and sort by type the images in the email message:

function milter_hook(ctx)

 …

 local images = {}
 for part, path in ctx.message.parts{content_type = "image/*"} do
  local subtype = part.content_type.subtype
  images[subtype] = (images[subtype] or 0) + 1
 end

 for t, c in pairs(images) do
  dw.notice("Found " .. t .. " images: " .. c)
 end

 …

end

4.Write to the log the list of audio files found in the attachments:

function milter_hook(ctx)

 …

 for p, path in ctx.message.parts{
  content_type = "audio/*",
  content_disposition = {"inline", "attachment"}
 } do
    local name = p.name
    if name == "" then name = "<unnamed>" end
    dw.notice("Audio file: " .. name)
 end

 …

end

Table ScanReportFilter

The table describes the filter for reports of scanning message parts for threats (similar to the table FileFilter above). Contains the following fields (all fields are optional):

Field

Description

Data type

error

Error name to be added to the ScanReport; for instance: "password_protected", "scan_timeout".

Not case-sensitive.

String or table of strings

error_not

Error name that must not be added ScanReport; for instance: "password_protected", "scan_timeout".

Not case-sensitive.

String or table of strings

Overridden metamethods: None

If several filter fields are specified, then the condition is combined by a conjunction (logical AND). If the filter field is a table (array), the scan report must match at least one of the table (array) items. If the filter field is not specified (the value is nil), any scan report matches the filter.

Usage examples:

1.Quarantine the message in case of failed attempts to scan a password-protected archive:

function milter_hook(ctx)

 …

 if ctx.message.has_scan_report{error = 'password_protected'} then
   return
    {
      action = 'accept', deleted_recipients = ctx.to,
      added_recipients = {'quarantine@mail.domain.com'}
    }
 end

 …

end

2.Quarantine the message if the scan limits have been exceeded:

function milter_hook(ctx)

 …

 local limit_errors = {
  'archive_level_limit', 'compression_limit',
  'container_level_limit', 'mail_level_limit',
  'packer_level_limit', 'report_size_limit'
 }

 if ctx.message.has_scan_report{error = limit_errors} then
   return
    {
      action = 'accept', deleted_recipients = ctx.to,
      added_recipients = {'quarantine@mail.domain.com'}
    }
 end

 …

end

3.Reject the message in case of scan errors:

function milter_hook(ctx)

 …

 if ctx.message.has_scan_report{error = '*'} then
   return {action = 'reject'}
 end

 …

end

Table MimeHeader

The table describes the message part headers.

Field

Description

Data type

field

List of headers and their values

Array of HeaderField tables

search

Function that searches for header by regular expression (PCRE). It takes a regular expression (string) as an argument. The search is performed in all the headers of the message part. Note that if you use strings in the quotation marks, the slash character must be escaped.

Returns a Boolean value:

true—if the field.name .. ": " .. field.value.decoded string matches the specified regular expression for at least one of the headers;

false—if the field.name .. ": " .. field.value.decoded string does not match the specified regular expression for at least one of the headers

Function

value

Function that returns the value of the specified header. It takes the name of header (string) as an argument.

The function returns the HeaderFieldValue table that corresponds to the first header with the specified name found, or nil if the header has not been found.

Function

Overridden metamethods: None

Table HeaderField

The table describes the message part header.

Field

Description

Data type

name

Header name

String

value

Header value

Table HeaderFieldValue

url

List of URLs found in the header value (only for the Subject header), for all other headers—nil

Array of Url tables

Overridden metamethods: None

Table HeaderFieldValue

The table describes the value of the email message header.

Field

Description

Data type

raw

Raw (undecoded) header value

String

decoded

Decoded header value

String

Overridden metamethods:

__toString—the function returns the HeaderFieldValue content (the decoded field value) as a string;

__concat—the function concatenates HeaderFieldValue (the decoded field value) and another string.

Table MimeBody

The table describes the message part body.

Field

Description

Data type

raw

Raw (undecoded) body of the message part

String

decoded

Decoded value of the message part body (according to the value of the Content-Transfer-Encoding and Content-Type headers)

String

text

Decoded value of the message part body in the UTF-8 according to the charset parameter of the Content-Type header.

It is present only for the parts with "Content-Type: text/*" or with an empty Content-Type. Otherwise—nil.

String

scan_report

Threat scanning report

Table ScanReport

url

URLs found in the part text as an array of Url tables.

If the text field is absent (nil), the field is empty.

Array of Url tables

search

Function that searches for text in this body using a regular expression (PCRE). Takes a regular expression (string) as an argument. Note that if you use strings in the quotation marks, the slash character must be escaped.

Returns a Boolean value:

true—if the body is a text and a match has been found;

false—if no match has not been found in the body

Function

md5

MD5 hash of the email message body.

String

sha1

SHA1 hash of the email message body.

String

sha256

SHA256 hash of the email message body.

String

vxcube_analysis

Message analysis result from Dr.Web vxCube. The field is present only when in SMTP mode.

Array of VxcubeAnalysis tables

Overridden metamethods: None

Table ScanReport

The table contains a report about scanning for threats.

Field

Description

Data type

object

Name of the scanned object

String

archive

Information about the container, if the scanned object is a container. If the object is not a container, it is nil

The Archive table

virus

List of detected threats

Array of Virus tables

error

In case of an error, it contains a string with a scan error. Otherwise, it is nil. Allowed values:

"path_not_absolute"—the path indicated is not absolute;

"file_not_found"—the file was not found;

"file_not_regular"—the file is not a regular file;

"file_not_block_device"—it is not a block device;

"name_too_long"—the name is too long;

"no_access"—access denied;

"read_error"—reading error occurred;

"write_error"—a writing error;

"file_too_large"—the file is too large;

"file_busy"—file is being used;

"unpacking_error"— an unpacking error;

"password_protected"—the archive is password protected;

"arch_crc_error"—CRC archive error;

"arch_invalid_header"—invalid archive header;

"arch_no_memory"—not enough memory to unpack archive;

"arch_incomplete"—incomplete archive;

"can_not_be_cured"—file cannot be cured;

"packer_level_limit"—packed object nesting level limit exceeded;

"archive_level_limit"—archive nesting level limit exceeded;

"mail_level_limit"—mail file nesting level limit exceeded;

"container_level_limit"—container nesting level limit exceeded;

"compression_limit"—compression rate limit exceeded;

"report_size_limit"—report size limit exceeded;

"scan_timeout"—scan timeout limit exceeded;

"engine_crash"—scan engine failure;

"engine_hangup"—scan engine hangup;

"engine_error"—scan engine error;

"no_license"—no active license found;

"multiscan_too_late"—multiscanning error;

"curing_limit_reached"—cure attempts limit exceeded;

"non_supported_disk"—disk type is not supported;

"unexpected_error"—an unexpected error.

String

item

Report on the scanning of container attachments (if the object is a container, i.e. archive, attached MIME object, and so on)

Overridden metamethods: None

The Archive table

The table describes archives and other compound objects.

Field

Description

Data type

type

Archive type:

"archive"—archive;

"mail"—email file;

"container"—other container.

String

name

Archive name, for example, ZIP

String

Overridden metamethods: None

Table DKIM

The table describes all DKIM signatures in the message.

Field

Description

Data type

signature

List of DKIM signatures present in the message

Array of DKIMSignature tables

has_valid_signature

A function that takes filter as an argument and returns

the first found DKIM signature with the scan result that equals "pass" in the form of the DKIMSignature table;

nil appears if no signatures failing verification have been detected.

As the filter argument, you can use:

the DKIMSignatureFilter table;

arbitrary predicate function, that receives the only DKIMSignature argument and returns a Boolean value

otrue—if the argument meets the condition;

ofalse—if the argument does not meet the condition.

Function

Overridden metamethods: None

Table DKIMSignature

The table describes the properties of each DKIM signature in the message.

Field

Description

Data type

auid

The value Agent or User Identifier (AUID), obtained from the "i" tag of the DKIM signature, takes the default value into account

String

data

Text (base64) value of the signature extracted from the "b" tag of the DKIM signature

String

result

DKIM signature verification result

The DKIMResult table

sdid

The value Signing Domain Identifier (SDID), obtained from the "d" tag of the DKIM signature

String

selector

A selector, obtained from the "s" tag of the DKIM signature

String

Overridden metamethods: None

Table DKIMResult

The table describes the results of scanning for all DKIM signatures of the message.

Field

Description

Data type

type

DKIM signature verification result in the text format. It may have the following values:

pass indicates that signature verification has been successful;

fail indicates that signature verification has failed (i.e. it does not correspond with the hash of the email body or the signature could not be verified);

neutral is a syntax error of the DKIM signature;

temperror indicates a failed attempt at obtaining the domain key (DNS error);

permerror indicates other types of errors (signature format, key format, inconsistencies between the key and the signature, and so on).

String

comment

Comment on the scan result (can be used as a comment in Authentication-Results)

String

key_size

The key size used during the scan is either nil, or neutral if the attempt to obtain the key or the scan result has failed

Number

Overridden metamethods: None

Table DKIMSignatureFilter

The table describes the filter for DKIM message signatures (similar to the FileFilter table above). All fields are optional.

Field

Description

Data type

domain

A character set or a wildcard that the domain from the SDID field of the DKIM signature is expected to match

String or table of strings

domain_not

A character set or a wildcard that the domain from the SDID field of the DKIM signature is not expected to match

String or table of strings

Overridden metamethods: None

If the filter field is not specified (i.e. it contains the nil value), any DKIM signature of this message matches the filter. If several filter fields are specified, then the conditions are combined by conjunction (logical “AND”). If the filter field type is a table (array), then the filtered object must match at least one of the table (array) elements.

Table SPF

The table contains all the data necessary for checking SPF.

Field

Description

Data type

helo

The result of HELO check

from

The result of MAIL FROM check

check()

An auxiliary function; first performs the MAIL FROM check and then (if no verdict has been received)—the HELO check. The function returns the result of the check as a string that may have the same values as that of the status field in the SPFResult table.

The function is designed for transmitting the results to OpenDMARC via the generated Authentication-Results header

Function

Overridden metamethods: None

Table SPFResult

A table containing the result of checking SPF.

Field

Description

Data type

status

The result of the check represented as a string. It can have one of the following values (according to RFC 7208): none, neutral, pass, fail, softfail, temperror, permerror

String

explanation

The explanation of the result in case the fail response has been received.

String or nil if no explanation was received or it was impossible to get it

Overridden metamethods: None

Table VxcubeAnalysis

The table contains the result of object analysis in Dr.Web vxCube.

Field

Description

Data type

filename

The name of the analyzed attachment

String

id

Analysis ID

String

sample_id

Analyzed file ID

String

format_name

Analyzed file format

String

tasks

Analysis result

Array of VxcubeTask tables

max_maliciousness

Maximum value of the maliciousness field from the array of VxcubeTask tables. Can be a float from 0 to 100, or nil if there was an error.

Number or nil

Overridden metamethods: None

Table VxcubeTask

The table contains the result of object analysis performed on a certain platform in Dr.Web vxCube. The table structure is roughly equivalent to the TaskFinished object received via the Dr.Web vxCube API.

Field

Description

Data type

id

Task ID

String

status

Analysis status, such as "failed" or "finished"

String

platform_code

Code of the platform that the analysis was performed on. nil if there was an error.

String or nil

maliciousness

Maliciousness of the object. Can be a float from 0 to 100, or nil if there was an error.

Number or nil

verdict

Overall file maliciousness score corresponding to one of the three categories in the format of <category><degree>, where <category> is one of the following values: "neutral", "suspicious", "malware"; <degree> is an integer that represents the maliciousness degree (1 to 3). Examples of the verdict value: "malware1", "suspicious3".

String

Overridden metamethods: None

Available Auxiliary Modules

For interconnection with Dr.Web for UNIX Mail Servers in program space in Lua the following specific modules can be imported.

Name of the module

Function

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

Provides tools to request data from external sources by calling the Dr.Web LookupD module

Provides tools to check if the hosts’ addresses are in the DNSxL black lists

Provides an interface to match strings and regular expressions

Provides an interface to run external applications (processes)

Provides a table with the Dr.Web MailD configuration parameter values

Provides functions to store data between MailD runs

Contents of the drweb Module

1.Functions

The module provides a set of functions.

Saving messages from the Lua program in the Dr.Web for UNIX Mail Servers component log:

log(<level>, <message>) writes the <message> string to the Dr.Web for UNIX Mail Servers log on the <level> level (the required level is defined using the “debug”, “info”, “notice”, “warning”, and “error”);

debug(<message>) writes the <message> string to the Dr.Web for UNIX Mail Servers log at the DEBUG level;

info(<message>) writes the <message> string to the Dr.Web for UNIX Mail Servers log at the INFO level;

notice(<message>) writes the <message> string to the Dr.Web for UNIX Mail Servers log at the NOTICE level;

warning(<message>) writes the <message> string to the Dr.Web for UNIX Mail Servers log at the WARNING level;

error(<message>) writes the <message> string to the Dr.Web for UNIX Mail Servers log at the ERROR level.

Managing the synchronization of Lua procedures:

sleep(<sec.>) pauses the execution of a Lua procedure instance for a specified number of seconds.

async(<Lua function>[, <argument list>]) launches the specified function asynchronously and passes to it the specified argument list. The async function call completes immediately, and the return value (the table Future) allows you to obtain the result of the <Lua function>.

Adding IP addresses to the IpAddress table:

ip(<address>) indicates an IP address, sent as the <address> string in the form of an IpAddress table. Either IPv4 or IPv6 addresses can be used.

Uploading external data from a text file:

load_set(<file path>) generates a table with the true values from the contents of the specified text file; strings read from a file are used as keys. Empty strings as well as strings with blank spaces will be ignored;

load_array(<file path>) generates a string array from the contents of the specified text file. Empty strings and strings consisting of whitespace characters only, are ignored and are not included in the array.

2.Tables

The Future table describes the pending result of performing a function using the async function.

Field

Description

Data type

wait

A function that returns the result of the function started using the async.function If the function has not completed its execution yet, it waits for the completion and returns the result. If the function is completed before wait is called, the result is returned immediately. If the started function fails, the wait call generates the same error.

Function

Overridden metamethods: None

The IpAddress table describes an IP address.

Field

Description

Data type

belongs

Function checks an IP address stored in the IpAddress table for belonging to the specified subnets (IP address ranges).

Receives the only argument—a string that looks like: "<IP address>" or "<IP address>/<mask>", where <IP address>—a host address or a network address (for example, "127.0.0.1"), and <mask>—a subnetwork mask (can be specified as an IP address, for example, "255.0.0.0", or in the numerical form, for example, "8").

Returns a Boolean value:

true indicates that the address equals to at least one of the specified addresses or belongs at least one of the specified subnets (range of IP addresses);

false—otherwise.

Function

Overridden metamethods:

__tostring is a function that modifies IpAddress in a string, for example: "127.0.0.1" (IPv4) or "::1" (IPv6);

__concat is a function that performs joining IpAddress to a string;

__eq is a function that checks the equality of two IpAddress;

__band—function that allows to apply a mask, for example: dw.ip('192.168.1.2') & dw.ip('255.255.254.0')

3.Examples

Writing the messages generated by a procedure initiating asynchronously to the log:

local dw = require "drweb"

-- This function waits two seconds and returns a string,
-- received as an argument
function out_msg(message)
 dw.sleep(2)
 return message
end

-- "Main" function
function intercept(ctx)
 -- Output of a string at the NOTICE level to the Dr.Web for UNIX Mail Servers log
 dw.notice("Intercept function started.")

 -- An asynchronous start of two copies of the out_msg function
 local f1 = dw.async(out_msg, "Hello,")
 local f2 = dw.async(out_msg, " world!")

 -- Waiting for the completion of the copies of the function
 -- out_msg and output its results to log
 -- the Dr.Web for UNIX Mail Servers log at the DEBUG level
 dw.log("debug", f1.wait() .. f2.wait())
end

Creating a scheduled procedure:

local dw = require "drweb"

-- Save the table Future in the future global variable in order
-- to preven the removal by the garbage collector
future = dw.async(function()
   while true do
     -- Everyday, the following message is displayed in the log
     dw.sleep(60 * 60 * 24)
     dw.notice("A brand new day began")
   end
end)

Modifying an IP address represented as a string into an IpAddress table::

local dw = require "drweb"

local ipv4 = dw.ip("127.0.0.1")
local ipv6 = dw.ip("::1")
local mapped = dw.ip("::ffff:127.0.0.1")

 

Contents of the drweb.lookup Module

1.Functions

The module provides the following functions:

lookup(<request>, <parameters>) requests data from an external storage available via the Dr.Web LookupD module. The <request> argument must correspond to a section in the Dr.Web LookupD settings (the string <type>@<tag>). The <parameters> argument is optional. It describes substitutions that will be used to generate a request. The following automatically permitted markers can be used:

$u, $U is automatically replaced with user, the user name sent by the client component;

$d, $D is automatically replaced with domain, the domain sent by the client component.

These arguments are set as a table. Keys and values of this table must be strings. The function returns an array of strings that are results of the request;

check(<checked string>, <request>, <parameters>) returns true if <checked string> is found in the external repository, available via the Dr.Web LookupD module. The arguments <request> and <parameters> are equivalent to the arguments of the lookup function (see above). The <checked string> argument is supposed to be a string or a table with the __tostring metamethod (i.e. that can be formatted into a string).

2.Examples

Writing to the log list of users retrieved from the LookupD.LDAP.users data source:

local dw = require "drweb"
local dwl = require "drweb.lookup"

-- "Main" function
function intercept(ctx)
 -- Writing the string at the NOTICE level to the Dr.Web for UNIX Mail Servers log
 dw.notice("Intercept function started.")

 -- Writing the request results to the Dr.Web for UNIX Mail Servers log
 -- to the 'ldap@users' data source
 for _, s in ipairs(dwl.lookup("ldap@users", {user="username"})) do
   dw.notice("Result for request to 'ldap@users': " .. s)
 end

end

 

Contents of the drweb.dnsxl Module

1.Functions

The module provides the following functions:

ip(<IP address>, <DNSxL server>) requests DNS records of an A type from the DNSxL server <DNSxL server> that correspond to the specified IP address <IP address>.

If an IP address that is being checked is registered in the lists of the DNSxL server, then the result is a list of fictitious IP addresses. At that, each of the returned fictitious IP addresses can contain the reason for which the checked <IP address> is listed in the lists of this server (usually the reason type is determined by the value of the last octet of a returned fictitious IP address). If the DNSxL server does not contain the DNS records of an A type, for the IP address <IP address>, the function returns nil.

url(<URL>, <SURBL server>) requests DNS records of an A type from the <SURBL server> server that correspond to the <URL> domain part (HTTP redirecting is not processed).

If the domain that is being checked, retrieved from <URL>, is registered in server lists of the SURBL server, then the result is a list of fictitious IP addresses. At that, each of the returned fictitious IP addresses can contain the reason for which the checked domain is listed in the lists of this server (usually the reason type is determined by the value of the last octet of a returned fictitious IP address). If the SURBL server does not contain the DNS records of an A type for domains from <URL>, the function returns nil.

Function arguments are strings or objects casted to strings (for example, as <IP address >, the IpAddress table can be used, and as <URL>—the Url table). IP addresses are returned as an array of the IpAddress tables.

2.Tables

The IpAddress table describes the IP address. You can find the description of the table above.

3.Examples

Output the results of the IP address scanning by the DNSxL server to the log:

local dw = require "drweb"
local dwxl = require "drweb.dnsxl"

-- "Main" function
function intercept(ctx)
 -- Output of a string at the NOTICE level to the Dr.Web for UNIX Mail Servers log
 dw.notice("Intercept function started.")

 -- Output of the scanning results to the Dr.Web for UNIX Mail Servers log
 -- 10.20.30.40 IP addresses are in the DNSxL server black list
 -- dnsxl.server1.org
 local records = dwxl.ip("10.20.30.40", "dnsxl.server1.org")
 if records then
   for _, ip in ipairs(records) do
    dw.notice("DNSxL A record for 10.20.30.40: " .. ip)
   end
 end

end

 

Contents of the drweb.regex Module

1.Functions

The module provides the following functions:

search(<template>, <text>[, <flags>]) returns true if the <text> string contains a substring that matches the <template> regular expression. The optional <flags> parameter (integer) is a set of flags affecting the function behavior connected with the logical OR.

match(<template>, <text>[, <flags>])—the same as search except that the <template> regular expression must match the entire <text> string, not only its substring.

2.Available flags

ignore_case ignores text case.

3.Examples

local rx = require "drweb.regex"

rx.search("te.?t", "some TexT") -- false
rx.search("te.?t", "some TexT", rx.ignore_case) -- true

rx.match("some.+", "some TexT") -- true

 

Contents of the drweb.subprocess Module

1.Functions

The module provides the function:

run(<parameters >) runs the specified process (application) in the synchronous mode (the function gives control back only after the process exit). The <parameters> argument is a table that contains an executable path to the file, all arguments passing to the application at its launch (array argv), and optional parameters associated with the application input/output streams (stdin, stdout, stderr) that specify the working (current) directory of the application and environment variables.

The function result is a table that contains results of the process operation after its exit: exit code or signal number, at which the process was terminated. Moreover, returned table can contain fields with data that are read from the stdout and stderr output streams if they are specified in the table of the process running parameters.

2.Tables

Table of input run parameters

Field

Description

Data type

(without name)

File path and application run arguments (array argv).

Required field. Field is repeated the number of the command-line arguments, the first value corresponds to argv[0], i.e. executable path.

String

stdin

Text that the application (process) will receive from the input stream (stdin) after its run. Optional field (if not specified, stdin will not receive anything).

String

stdout

Name of the field of the returned table. The field will receive the text that the process output to the stdout stream. Optional field (if not specified, the output will not be saved in stdout).

String

stderr

Name of the field of the returned table. The field will receive the text that the process output to the stderr stream. Optional field (if not specified, the output will not be saved in stderr).

String

env

Table whose fields are the environment variables that will be sent to the process environment. The environment variables are specified as pairs "<variable name>"="<value>". Optional field (if not specified, the environment variables are not set).

Table

workdir

Working (current) directory for the running process. Optional field (if not specified, the working directory is not set).

String

Table of run results (the return value of the run function)

Field

Description

Data type

exit_status

Return code, with which the process exited successfully. Otherwise, it is nil.

Number

exit_signal

Signal number at which the process was terminated. Otherwise, it is nil.

Number

(value of the stdout field of the table of input parameters)

Data read from the stdout stream of an exited process. Field is available only if the stdout field is specified in the table of input parameters.

String

(value of the stderr field of the table of input parameters)

Data read from the stderr stream of an exited process. Field is available only if the stderr field is specified in the table of input parameters.

String

3.Examples

To run the cat utility without arguments, to pass the 'some data' text to its input stream, and to pass the command output results to the stdout_field field of the returning table:

local sp = require 'drweb.subprocess'

local cat_result = sp.run({
   '/bin/cat',
   stdin = 'some data',
   stdout = 'stdout_field',
})

Table of the result stored in the cat_result variable contains the following fields:

Field

Valueexit_status

exit_status

0

exit_signal

nil

stdout_field

'some data'

To run the sh command (command interpreter) with the and env | grep TESTVAR 1>&2 parameters (command run by the interpreter), to add the TESTVAR variable with the VALUE value to the environment, and to pass the command stderr output result to the stderr_field field of the returning table:

local sp = require 'drweb.subprocess'

local env_result = sp.run({
   '/bin/sh', '-c', 'env | grep TESTVAR 1>&2',
   env = { TESTVAR = 'VALUE' },
   stderr = 'stderr_field'
})

Table of the result stored in the env_result variable contains the following fields:

Field

Valueexit_status

exit_status

0

exit_signal

nil

stderr_field

'TESTVAR=VALUE\n'

To run the pwd command and to set the working directory to the system root directory, and to pass the command stdout output results to the stdout_field field of the returning table:

local sp = require 'drweb.subprocess'

local pwd_result = sp.run{
   '/bin/pwd',
   workdir = '/',
   stdout = 'stdout_field'
}

Table of the result stored in the pwd_result variable includes the following fields:

Field

Valueexit_status

exit_status

0

exit_signal

nil

stdout_field

'/\n'

To run the kill command in bash and to pass the SIGKILL signal to the interpreter:

local sp = require 'drweb.subprocess'

local kill_result = sp.run{'/bin/bash', '-c', 'kill -9 $$'}

Table of the result stored in the kill_result variable includes the following fields:

Field

Valueexit_status

exit_status

nil

exit_signal

9

To run the process asynchronously, run the run function inside the async function call (see above).

Contents of the drweb.config Module

1.Functions

The module does not provide any functions.

2.Available tables

The module provides the table MailDConfig with the following fields:

Field

Description

Data type

version

Dr.Web MailD version

String

Overridden metamethods: None

The MailDConfig table is provided by the module as the maild field.

3.Examples

Output to log the current version of the Dr.Web MailD component:

local dw  = require 'drweb'
local cfg = require 'drweb.config'

-- "Main" function
function milter_hook(ctx)

 -- Output of a string at the NOTICE level to the Dr.Web for UNIX Mail Servers log
 dw.notice(cfg.maild.version)

end

 

Contents of the drweb.store Module

1.Functions

The module provides the following functions:

exists (<name>, <key>) checks if there is an entry with the specified key in the selected repository. Takes two arguments: <name> (string)—the name of the repository; <key> (string)—the key of the entry. Returns true if there is an entry, otherwise returns false;

get (<name>, <key>) obtains the value of the entry with the specified key from the selected storage. Takes two arguments: <name> (string)—the name of the repository; <key> (string)—the key of the entry. Returns a pair with parameters: value, ctime; or nil if there is no entry. The value parameter (string)—the value of the entry with the specified key; ctime (integer)—record modification timestamp;

put (<name>, <key>, <value>) adds an entry with the specified key to the selected storage. It takes three arguments: <name> (string)—the name of the repository; <key> (string)—the key of the entry, <value> (string)—the value of the entry;

remove (<name>, <key>) removes the entry with the specified key from the selected storage. Takes two arguments: <name> (string)—the name of the repository; <key> (string)—the key of the entry;

count (<name>) returns the number of records in the selected storage. Takes one argument: <name> (string)—the name of the repository. Returns an integer;

drop (<name>, <ctime>) removes from the selected storage all entries that were modified before the specified timestamp. Takes two arguments: <name> (string)—the name of the repository; ctime (integer)—timestamp of the entry modification.

2.Examples

Creating a white list for anti-spam scans:local store = require "drweb.store"

local store = require "drweb.store"

local antispam_whitelist = "antispam_whitelist"
local intra_domain_mask = ".*@test%.test$"

-- "Main" function
function milter_hook(ctx)

 -- Add all the outgoing mails recipients
 -- to the anti-spam white list
 if ctx.from:match(intra_domain_mask) then
   for _, to in ipairs(ctx.to) do
    store.put(antispam_whitelist, to, "")
   end
   return {action="accept"}
 end

 if not store.exists(antispam_whitelist, ctx.from) then
   if ctx.message.spam.score > 300 then
    return {action="reject"}
   end
 end

 return {action="accept"}

end

Temporary addition to the white list:

local store = require "drweb.store"

local antispam_whitelist = "antispam_whitelist"
local antispam_whitelist_timeout = 604800 -- 1 week
local intra_domain_mask = ".*@test%.test$"

-- "Main" function
function milter_hook(ctx)

 -- Add all the outgoing mails recipients
 -- to the anti-spam white list
 if ctx.from:match(intra_domain_mask) then
   for _, to in ipairs(ctx.to) do
    store.put(antispam_whitelist, to, "")
   end
   return {action="accept"}
 end

 local _, ctime = store.get(antispam_whitelist, ctx.from)
 -- Is on the list and was added within a week
 local in_whitelist = ctime and os.time() + ctime < antispam_whitelist_timeout

 if not in_whitelist and ctime then
   store.remove(antispam_whitelist, ctx.from)
 end

 -- You can also update a non-expired entry:
 -- if in_whitelist then
 --  store.put(antispam_whitelist, ctx.from, "")
 -- end

 if not in_whitelist then
   if ctx.message.spam.score > 300 then
    return {action="reject"}
   end
 end

 return {action="accept"}

end