![]() |
![]() |
![]() |
![]() |
This document describes how to write milter-manager.conf that is milter-manager's configuration file.
It assumes that milter-manager is installed under /usr/local/. If you specify --prefix=/usr/local option to configure script or omit the option, milter-manager is installed under /usr/local/.
In this case, milter-manager's configuration file is placed at /usr/local/etc/milter-manager/milter-manager.conf. If you have installed successfully, the file should exist.
The beginning milter-manager.conf is the following:
# -*- ruby -*- load("applicable-conditions/*.conf") load_default load_if_exist("milter-manager.local.conf")
Normally, the part should not be changed. If you need to change your configuration, you should write your configurations to "milter-manager.local.conf" file in the same directory of "milter-manager.conf".
Configuration items are categorized as the followings:
There is a convenient feature of milter-manager. It's introduced before each items are described the below.
If you run milter-manager with --show-config option, the current configuration is shown.
% /usr/local/sbin/milter-manager --show-config package.platform = "debian" package.options = nil security.privilege_mode = false security.effective_user = nil security.effective_group = nil log.level = "default" log.path = nil log.use_syslog = true log.syslog_facility = "mail" manager.connection_spec = nil manager.unix_socket_mode = 0660 manager.unix_socket_group = nil manager.remove_unix_socket_on_create = true manager.remove_unix_socket_on_close = true manager.daemon = false manager.pid_file = nil manager.maintenance_interval = 10 manager.suspend_time_on_unacceptable = 5 manager.max_connections = 0 manager.custom_configuration_directory = nil manager.fallback_status = "accept" manager.fallback_status_at_disconnect = "temporary-failure" manager.event_loop_backend = "glib" manager.n_workers = 0 manager.packet_buffer_size = 0 manager.connection_check_interval = 0 manager.chunk_size = 65535 manager.max_pending_finished_sessions = 0 controller.connection_spec = nil controller.unix_socket_mode = 0660 controller.remove_unix_socket_on_create = true controller.remove_unix_socket_on_close = true define_applicable_condition("S25R") do |condition| condition.description = "Selective SMTP Rejection" end define_applicable_condition("Remote Network") do |condition| condition.description = "Check only remote network" end
You can confirm the current configuration.
The output format is the same as milter-manager.conf's syntax. You can refer the output for writing milter-manager.conf.
Here are descriptions of configuration items.
Normally, this item doesn't need to be changed. milter auto-detect method is different on each platform. The auto-detect method assumes that milters are installed with package system on its platform. If real platform and platform detected by milter-manager are different, the auto-detect method doesn't work well. Your platform is detected on building milter-manager. You can specify correct platform if the detected platform is wrong. You will use this item only when the detected platform is wrong but you can't build again. Here are supported platforms:
Platform name should be surrounded with '"' (double quote) like "debian". NOTE: This item should be changed before load_default. Example: package.platform = "pkgsrc" Default: package.platform = "debian" # depend on your environment. |
|
Normally, this item doesn't need to be changed. This item is determined on building like package.platform. You can pass additional information to milter auto-detect method. The format of this item is "NAME1=VALUE1,NAME2=VALUE2,...". You can pass zero or more information. Currently, additional information is only used on "pkgsrc" platform. "pkgsrc" platform only uses "prefix=/PATH/TO/DIRECTORY/HAS/rc.d". For example, you need to specify "prefix=/etc" if you install start-script under /etc/rc.d/ directory. NOTE: This item should be changed before load_default. Example: package.options = "prefix=/etc,name=value" Default: package.options = nil # depend on your environment. |
Specifies whether run as privilege mode or not. If you want to use child milter auto run feature, you need to enable the mode. It's set true for enabling the mode, false otherwise. Example: security.privilege_mode = true Default: security.privilege_mode = false |
|
Specifies effective user of milter-manager process. To switch effective user, you need to run milter-manager command as root user. Effective user is specified like "nobody". User name should be surrounded with '"' (double quote). If you don't want to specify user, use nil. Example: security.effective_user = "nobody" Default: security.effective_user = nil |
|
Specifies effective group of milter-manager process. To switch effective group, you need to run milter-manager command as root group. Effective group is specified like "nogroup". Group name should be surrounded with '"' (double quote). If you don't want to specify group, use nil. Example: security.effective_group = "nobody" Default: security.effective_group = nil |
Since 1.6.6.
Specifies log level. All log levels are independent. You can specify log level by combining log levels what you need like "info, debug and error levels are needed". Here are available log levels:
Log level should be surrounded with '"' (double quote) like "all". To specify some log levels, you need to separate each log level by "|" like "critical|error|warning". Example: log.level = "all" # Logs all messages Default: log.level = "default" |
|||||||||||||||||||||||||||||||||||
Specifies the log output file path. If the value is nil, log is outputted to the standard output. Example: log.path = nil # Output to the standard output log.path = "/var/log/milter-manager.log" # Output to the file Default: log.path = nil |
|||||||||||||||||||||||||||||||||||
Specifies whether syslog is also used. Set true for using syslog, false otherwise. Example: log.use_syslog = false # Syslog isn't used. Default: log.use_syslog = true |
|||||||||||||||||||||||||||||||||||
Specifies syslog facility. Here are available facilities and corresponded syslog constants:
Facility should be surrounded with '"' (double quote) like "mail". Example: log.syslog_facility = "local4" # LOG_LOCAL4 is used. Default: log.syslog_facility = "mail" |
Specifies a socket that milter-manager accepts connection from MTA. Socket is specified like "inet:10025". Socket should be surrounded with '"' (double quote). Available socket formats are the following:
If security.effective_user and/or security.effective_group are specified, UNIX domain socket is made with the authority. If HOST of IPv4 socket and IPv6 socket is omitted, milter-manager accepts connection from all network interface. If HOST is specified, milter-manager accepts connection from the address. Example: manager.connection_spec = "unix:/var/run/milter/milter-manager.sock" Default: manager.connection_spec = "inet:10025@[127.0.0.1]" |
|||||||||
Specifies permission of UNIX domain socket that milter-manager uses for accepting connection. This is used only when UNIX domain socket is specified for manager.connection_spec. Don't forget to prepend '0' to specify permission as octal notation. Example: manager.unix_socket_mode = 0600 Default: manager.unix_socket_mode = 0660 |
|||||||||
Specifies group of UNIX domain socket that milter-manager uses for accepting connection. This is used only when UNIX domain socket is specified for manager.connection_spec. Socket's group is changed by chown(2) after creating a socket with security.effective_user/security.effective_group authority. Specified group should be one of the security.effective_user's supplementary groups. Group is specified like "nogroup". Group name should be surrounded with '"' (double quote). If you don't want to specify group, use nil. Example: manager.unix_socket_group = "nobody" Default: manager.unix_socket_group = nil |
|||||||||
Specifies whether remove existing UNIX domain socket before creating new UNIX domain socket or not. This is used only when UNIX domain socket is specified for manager.connection_spec. True if remove, false otherwise. Example: manager.remove_unix_socket_on_create = false Default: manager.remove_unix_socket_on_create = true |
|||||||||
Specifies whether remove used UNIX domain socket after shutting down. This is used only when UNIX domain socket is specified for manager.connection_spec. True if remove, false otherwise. Example: manager.remove_unix_socket_on_close = false Default: manager.remove_unix_socket_on_close = true |
|||||||||
Specifies whether run as daemon process or not. This item doesn't need to set in configuration file because this item can be overridden by --daemon command line option. True if run as daemon process, false otherwise. Example: manager.daemon = true Default: manager.daemon = false |
|||||||||
Specifies file name where milter-manager saves its process ID. If security.effective_user and/or security.effective_group are specified, the file is wrote with the authority. You should take care permission of the file. File name is specified like "/var/run/milter/milter-manager.pid". File name should be surrounded with '"' (double quote). If you don't want to specify file name, use nil. Example: manager.pid_file = "/var/run/milter/milter-manager.pid" Default: manager.pid_file = nil |
|||||||||
Specifies maintenance process is ran after each N sessions. For now, the maintenance process is memory release process. It's a good choice that maintenance process is ran after each few sessions on few concurrently access environment. The configuration will keep memory usage low. It's a good choice that maintenance process is ran after each many sessions on many concurrently access environment. The configuration will keep process efficiency. 0 or nil means maintenance process is never ran. Example: manager.maintenance_interval = nil Default: manager.maintenance_interval = 10 |
|||||||||
Specifies how many seconds are suspended on milter-manager can't accept a connection from MTA. In the case, milter-manager has many connections. Please consider that you increment number of openable file descriptors by ulimit or limit in the case. Example: manager.suspend_time_on_unacceptable = 10 Default: manager.suspend_time_on_unacceptable = 5 |
|||||||||
Since 1.3.1. Specifies max concurrent connections. 0 means no limit. It's the default value. A newly connection is waited until an existing connection is closed when there are max concurrent connections. Number of the current existing connections are confirmed each manager.suspend_time_on_unacceptable seconds. Example: manager.max_connections = 10 # accepts only 10 connections concurrency Default: manager.max_connections = 0 # no limit |
|||||||||
Since 1.3.1. Specifies max number of file descriptors that can be opened by a milter-manager process. 0 means that the system default is used. The system is used by default because the default value is 0. milter-manager opens "number of child milters + 1 (for MTA)" file descriptors for each connection. milter-manager also opens a few file descriptors for its internal usage. milter-manager should be able to open number of file descriptors computed by the following expression: (number of child milters + 1) * max concurrent connections + 10(milter-manager internal usage + alpha) This value is used as soft limit and hard limit by setrlimit(2). Example: manager.max_file_descriptors = 65535 Default: manager.max_file_descriptors = 0 |
|||||||||
Specifies a directory to save custom configuration via Web interface. Directory name is specified like "/tmp/milter-manager". Directory name should be surrounded with '"' (double quote). If you specify 'nil', milter-manager creates ".milter-manager" directory under effective user's home directory and use it for custom configuration directory. Example: manager.custom_configuration_directory = "/tmp/milter-manager/" Default: manager.custom_configuration_directory = nil |
|||||||||
Since 1.6.3. Specifies a status that is replied to the SMTP server on error in milter manager. Here is a list of error cases in milter manager:
Here are available values:
Example: manager.fallback_status = "reject" Default: manager.fallback_status = "accept" |
|||||||||
Since 1.6.3. Specifies a status that is replied to the SMTP server when milter manager detects the SMTP client disconnects the SMTP server connection. This item doesn't used by default because disconnect check is disabled by default. You can enable disconnect check by manager.use_netstat_connection_checker . Here are available values:
Example: manager.fallback_status_at_disconnect = "discard" Default: manager.fallback_status_at_disconnect = "temporary-failure" |
|||||||||
Normally, this item doesn't need to be used. Since 1.6.3. Specifies a backend for event loop. For non-large mail system which processes 100 or less mails per second, you don't need to change it. For large mail system which processes 100 or more mails per seconds, you need to change it to "libev". NOTE: For the sake of implemenation, glib backend uses callback. Note that glib's callback registration upper limit makes the limitation of the number of communications. This limitations exist against glib backend only. Here are availble values:
Example: manager.event_loop_backend = "libev" Default: manager.event_loop_backend = "glib" |
|||||||||
Normally, this item doesn't need to be used. Since 1.6.3. Specifies the number of processes which process mails. For non-large mail system which processes 100 or less mails per second, and mail system which doesn't use very heavy milter, you don't need to change it. For large mail system which processes 100 or more mails per seconds using very heavy milters, you need to increase it. Availble value is between 0 and 1000. If it is 0, no worker processes will be used. Example: manager.n_workers = 10 Default: manager.n_workers = 0 # no worker processes. |
|||||||||
Normally, this item doesn't need to be used. Since 1.6.3. Specifies buffer size to buffer send packets on end-of-message. Packets aren't sent until amount of buffered packets is greater than buffer size. 0 means buffering is disabled. It may improve performance when many message modification operations, add_header, delete_recipient and so on, are requested on end-of-message. Normary, this configuration doesn't improve performance. Example: manager.packet_buffer_size = 4096 # Doesn't send packets # until amount of # buffered packets >= 4KB. Default: manager.packet_buffer_size = 0 # Disables buffering. |
|||||||||
Normally, this item doesn't need to be used. Since 1.8.0. Specifies chunk size on body data for 2..n child milters. The maximum size is 65535 bytes and it is the default. If chunk size is decreased, communication overhead is incrased. You should use it only if you want to decrease each data size. Example: manager.chunk_size = 4096 # Sends body data as 4KB chunks. Default: manager.chunk_size = 65535 # Sends body data as 64KB chunks. |
|||||||||
Normally, this item doesn't need to be used. Since 1.8.6. Milter manager delays processings that don't effect to throughput until idle time. For example, termination processing for finished milter session is one of those delayed processings. Milter manager does termination processing for finished milter sessions by setting this item. Normally, there is idle time even when milter manager processes multiple milter sessions concurrently. If the number of processing milter sssions is too large, there will be no idle time. So termination processins are not done. If termination processings are not done for a long time, the number of openable file descripters may be lacked. Because used socket is closed in termination processing. Normally, you should avoid the no idle time situation because it is overload. It is better that increasing the number of workers by manager.n_workers configuration. Milter manager does termination processing even when there is no idle time by setting one or larger number. Termination processing is done when specified the number of finished sessions. This item doesn't disable termination processing on idle time. So this item doesn't effect to throughput on normal time. This item effects on only no idle time. The default value is 0. It distables termination processing on no idle time feature. Example: # Do termination processing after each session is finished manager.max_pending_finished_sessions = 1 Default: # Do termination processing when no other processings aren't remining manager.max_pending_finished_sessions = 0 |
|||||||||
Since 1.5.0. Checks SMTP client and SMTP server are still connected by parsing netstat command result. This feature is useful for aborting SMTP session when SMTP client disconnects SMTP session. e.g. Using taRgrey with milter (milter-greylist). This feature resolves a problem of taRgrey that SMTP server process is grown. SMTP server process growth means memory usage growth. i.e. This feature reduces memory usage caused by taRgrey. SMTP session is checked in 5 seconds. The interval time can be changed but it's not needed normally. Example: manager.use_netstat_connection_checker # check in 5 seconds. manager.use_netstat_connection_checker(1) # check in 1 seconds. Default: Don't check. |
|||||||||
Normally, this item doesn't need to be used directly. Since 1.5.0. Specifies an interval in seconds to check whether a connection between SMTP client and SMTP server is still connected. 0 means 'no check'. manager.define_connection_checker defines how to check whether a connection is still connected. Example: manager.connection_check_interval = 5 # Check in 5 seconds. Default: manager.connection_check_interval = 0 |
|||||||||
manager.define_connection_checker(name) {|context| ... # -> true/false} |
Normally, this item doesn't need to be used directly. Since 1.5.0. Checks a SMTP client is still connected to a SMTP server each manager.connection_check_interval seconds. If given block returns true value, it means that the connection is still alive, otherwise it means that the connection had been closed.
Example: # It assumes that a connection from non local network # is always closed. manager.define_connection_checker("netstat-check") do |context| context.smtp_client_address.local? end |
||||||||
Since 1.5.0. Logs memory usage each maintenance process. Here is the output format but it may be changed in the feature: Mar 28 15:16:58 mail milter-manager[19026]: [statistics] [maintain][memory] (28048KB) total:6979 Proc:44 GLib::Object:18 Example: manager.report_memory_statistics |
|||||||||
Normally, this item doesn't need to be used directly. Since 1.5.0. Executes a custom process each maintenance process. Here is an example that logs a message each maintenance process. Example: manager.maintained do Milter::Logger.info("maintained!") end |
|||||||||
Normally, this item doesn't need to be used directly. Since 1.6.8. Executes a custom process on an event loop is created. An event loop is created only on initialization. Here is an example that registers a callback that logs a message at intervals of 1 second. Example: manager.event_loop_created do |loop| loop.add_timeout(1) do Milter::Logger.info("timeout!") true end end |
Specifies a socket that milter-manager accepts connection for controlling milter-manager. Format is same as manager.connection_spec. Example: controller.connection_spec = "inet:10026@localhost" Default: controller.connection_spec = nil |
|
Specifies permission of UNIX domain socket for controlling milter-manager. This is used only when UNIX domain socket is specified for controller.connection_spec. Don't forget to prepend '0' to specify permission as octal notation. Example: controller.unix_socket_mode = 0600 Default: controller.unix_socket_mode = 0660 |
|
Specifies whether remove existing UNIX domain socket for controlling milter-manager before creating new UNIX domain socket or not. This is used only when UNIX domain socket is specified for controller.connection_spec. True if remove, false otherwise. Example: controller.remove_unix_socket_on_create = false Default: controller.remove_unix_socket_on_create = true |
|
Specifies whether remove used UNIX domain socket for controlling milter-manager after shutting down. This is used only when UNIX domain socket is specified for controller.connection_spec. True if remove, false otherwise. Example: controller.remove_unix_socket_on_close = false Default: controller.remove_unix_socket_on_close = true |
This section describes about configuration items related with child milter.
Child milter is registered as the following syntax:
define_milter("NAME") do |milter| milter.XXX = ... milter.YYY = ... milter.ZZZ = ... end
For example, to register a milter that accepts connection at 'inet:10026@localhost' as 'test-milter':
define_milter("test-milter") do |milter| milter.connection_spec = "inet:10026@localhost" end
The following items can be used in 'define_milter do ... end'.
Required item is just only milter.connection_spec.
Specifies socket that the child milter accepts. This is required item . Format is same as manager.connection_spec. Example: milter.connection_spec = "inet:10026@localhost" Default: milter.connection_spec = nil |
|
Specifies description of the child milter. Description is specified like "test milter". Description is surrounded with '"' (double quote). Example: milter.description = "test milter" Default: milter.description = nil |
|
Whether use the child milter or not. True if use, false otherwise. Example: milter.enabled = false Default: milter.enabled = true |
|
Specifies a status that is used the child milter causes an error. Here are available values:
Example: milter.fallback_status = "temporary-failure" Default: milter.fallback_status = "accept" |
|
Since 1.3.1. Whether turn on evaluation mode or not. The child milter doesn't return its result on evaluation mode. It means the child milter doesn't affect the existing mail system. Graphs are still generated on evaluation mode because statistics are logged. True if evaluation mode is turned on, false otherwise. On false (default) case, message handling in milter session is aborted when a child milter returns "reject" because milter manager returns "reject" to MTA. On true case, message handling in milter session is continued when a child milter returns "reject" because milter manager doesn't return "reject" to MTA. You can use a condition that "a child milter returns 'reject'" in applicable conditions. Example: milter.evaluation_mode = true Default: milter.evaluation_mode = false |
|
Specifies applicable conditions for the child milter. The child milter is stopped if any condition isn't satisfied. The following command shows available applicable conditions: % /usr/local/sbin/milter-manager --show-config | grep define_applicable_condition define_applicable_condition("S25R") do |condition| define_applicable_condition("Remote Network") do |condition| In the above case, "S25R" and "Remote Network" are available. Some applicable conditions are available in default configuration. You can also define your original applicable condition. See Define applicable condition about how to define applicable condition. But defining applicable condition requires Ruby's knowledge. To specify multiple applicable conditions, you can use ",": milter.applicable_conditions = ["S25R", "Remote Network"] Example: milter.applicable_conditions = ["S25R"] Default: milter.applicable_conditions = [] |
|
Adds an applicable condition to the child milter. See milter.applicable_conditions about 'applicable condition'. Example: milter.add_applicable_condition("S25R") |
|
Specifies command that run the child milter. The child milter is ran by the command automatically when connecting milter.connection_spec is failed. It is enabled only if security.privilege_mode is true and milter-manager is ran. Command may be run script that is placed in /etc/init.d/ or /usr/local/etc/rc.d/. Command is specified like "/etc/init.d/milter-greylist". Command should be surrounded with '"' (double quote). If you don't want to run automatically, use nil. Example: milter.command = "/etc/init.d/milter-greylist" Default: milter.command = nil |
|
Specifies options to be passed to milter.command. Options are specified like "start". Options should be surrounded with '"' (double quote). If some options are specified, use "--option1 --option2" or ["--option1", "--option2"]. Example: milter.command_options = "start" milter.command_options = ["--option1", "--option2"] Default: milter.command_options = nil |
|
Specifies user name to run milter.command. User name is specified like "nobody". User name should be surrounded with '"' (double quote). If you want to run milter.command as root, use nil. Example: milter.user_name = "nobody" Default: milter.user_name = nil |
|
Specifies timeout in seconds for trying to connect to child milter. Example: milter.connection_timeout = 60 Default: milter.connection_timeout = 297.0 |
|
Specifies timeout in seconds for trying to write to child milter. Example: milter.writing_timeout = 15 Default: milter.writing_timeout = 7.0 |
|
Specifies timeout in seconds for trying to read from child milter. Example: milter.reading_timeout = 15 Default: milter.reading_timeout = 7.0 |
|
Specifies timeout in seconds for trying to wait response of xxfi_eom() from child milter. Example: milter.end_of_message_timeout = 60 Default: milter.end_of_message_timeout = 297.0 |
|
Since 1.8.1. Returns child milter's name specified by define_milter. |
There is convenient features to operate defined child milters. But the features require knowledge about Ruby a bit.
defined_milters returns a list of define child milter names.
define_milter("milter1") do |milter| ... end define_milter("milter2") do |milter| ... end defined_milters # => ["milter1", "milter2"]
It's easy that changing configuration of all child milter by this feature.
Here is an example that disabling all child milters:
defined_milters.each do |name| define_milter(name) do |milter| milter.enabled = false end end
Here is an example that removing all child milters:
defined_milters.each do |name| remove_milter(name) end
Removing differs from disabling. You need to redefine a milter again when you want to use a removed milter again.
Here is an example that adding "S25R" applicable condition to all child milters.
defined_milters.each do |name| define_milter(name) do |milter| milter.add_applicable_condition("S25R") end end
Returns a list of defined child milter names. Returned value is an array of string. Example: defined_milters # => ["milter1", "milter2"] |
|
Removes a child milter that is named as 'name'. You should use milter.enabled when you may reuse the child milter. Example: # Removes a milter that is defined as "milter1". remove_milter("milter1") |
Here are descriptions about built-in applicable conditions.
This applicable condition applies a child milter to only normal PC like SMTP client. A child milter isn't applied to MTA like SMTP client.
Here is an example that uses Rgrey technique. (NOTE: milter-greylist should have "racl greylist default" configuration.)
Example:
define_milter("milter-greylist") do |milter| milter.add_applicable_condition("S25R") end
See S25R how to determine a SMTP client is MTA or normal PC.
S25R rules will also match non normal PC host name. To avoid this false positive, you can create whitelist. google.com domain and obsmtp.com domain are in whitelist by default.
You can also create blacklist for normal PC host name that isn't matched to S25R rules.
You can customize S25R applicable condition by the following configurations:
Since 1.5.2.
S25R applicable condition treats a host name that
For example, the following configuration adds google.com domain to whitelist: s25r.add_whitelist(/\.google\.com\z/) The following configuration adds mx.example.com host to whitelist: s25r.add_whitelist("mx.example.com") [For power user] You can specify complex condition by block. S25R applicable condition passes a host name to the block. For example, the following configuration adds .jp top level domain while 8:00 a.m. to 7:59 p.m. to whitelist: s25r.add_whitelist do |host| (8..19).include?(Time.now.hour) and /\.jp\z/ === host end |
|
Since 1.5.2.
S25R applicable condition treats a host name that
NOTE: If a host is listed both whitelist and blacklist, S25R applicable condition give preference to whitelist over blacklist. That is, child milter isn't applied in the case.
For example, the following configuration adds evil.example.com domain to blacklist: s25r.add_blacklist(/\.evil\.example\.com\z/) The following configuration adds black.example.com host to blacklist: s25r.add_blacklist("black.example.com") [For power user] You can specify complex condition by block. S25R applicable condition passes a host name to the block. For example, the following configuration adds .jp top level domain while 8:00 p.m. to 7:59 a.m. to blacklist: s25r.add_blacklist do |host| !(8..19).include?(Time.now.hour) and /\.jp\z/ === host end |
|
Since 1.6.6.
If
Example: s25r.check_only_ipv4 = false # enabled for non IPv4 connection Default: S25R check is enabled only for IPv4. |
This applicable condition applies a child milter to only SMTP client that is connected from remote network.
Here is an example that mails from local network are skipped spam-check to avoid false detection:
Example:
define_milter("spamass-milter") do |milter| milter.add_applicable_condition("Remote Network") end
Local network means that not private IP address. e.g. 192.168.0.0/24. You can customize local network by the following configurations.
Since 1.5.0. Adds the specified IPv4/IPv6 address or IPv4/IPv6 network to local network. Child milter isn't applied to SMTP clients connected from local network. Example: # Don't apply child milters connections from 160.29.167.10. remote_network.add_local_address("160.29.167.10") # Don't apply child milters connections from # 160.29.167.0/24 network. remote_network.add_local_address("160.29.167.0/24") # Don't apply child milters connections from # 2001:2f8:c2:201::fff0. remote_network.add_local_address("2001:2f8:c2:201::fff0") # Don't apply child milters connections from # 2001:2f8:c2:201::/64 network. remote_network.add_local_address("2001:2f8:c2:201::/64") |
|
Since 1.5.0. Adds the specified IPv4/IPv6 address or IPv4/IPv6 network to remote network. Child milter is applied to SMTP clients connected from remote network. Example: # Apply child milters connections from 160.29.167.10. remote_network.add_remote_address("160.29.167.10") # Apply child milters connections from # 160.29.167.0/24 network. remote_network.add_remote_address("160.29.167.0/24") # Apply child milters connections from # 2001:2f8:c2:201::fff0. remote_network.add_remote_address("2001:2f8:c2:201::fff0") # Apply child milters connections from # 2001:2f8:c2:201::/64 network. remote_network.add_remote_address("2001:2f8:c2:201::/64") |
This applicable condition applies a child milter to authenticated SMTP client by SMTP Auth. MTA should send authentication related macros to a milter. Sendmail isn't needed additional configuration. Postfix needs the following additional configuration:
main.cf:
milter_mail_macros = {auth_author} {auth_type} {auth_authen}
Here is an example that authenticated SMTP client's mail, inner to outer mail, is Bcc-ed to be audited:
Example:
define_milter("milter-bcc") do |milter| milter.add_applicable_condition("Authenticated") end
This applicable condition applies a child miter to non-authenticated SMTP client by SMTP Auth. MTA should send authentication related macros to a milter. See also Authentication .
Here is an example that only non-authentication SMTP client is applied spam-check to avoid false detection.
Example:
define_milter("spamass-milter") do |milter| milter.add_applicable_condition("Unauthenticated") end
This applicable condition is a bit strange. This always applies a child milter. This substitute different macros between Sendmail and Postfix. A milter that depends on Sendmail specific macros can be worked with this applicable condition and Postfix.
This applicable condition will be needless in the near feature because milters are fixing to be work with both Sendmail and Postfix. It's good things.
You can use this applicable condition with Postfix, it doesn't have adverse affect for Postfix.
Here is an example that you use milter-greylist built for Sendmail with Postfix.
Example:
define_milter("milter-greylist") do |milter| milter.add_applicable_condition("Sendmail Compatible") end
Since 1.5.0.
Those applicable conditions changes process depends on stress dynamically. Stress is determine by number of concurrent connections.
Since 1.5.0. Returns number of concurrent connections to determine stressed. With Postfix, number of max smtpd processes are detected automatically and 3/4 of it is set. With Sendmail, it's not detected automatically. You need to set it with stress.threshold_n_connections= by hand. Example: # Postfix's default. (depends on our environment) stress.threshold_n_connections # => 75 |
|
stress.threshold_n_connections=(n) |
Since 1.5.0. Sets number of connections to determine stressed. 0 means that always non-stressed. Example: # Number of concurrent connections is higher or equal # 75 means stressed. stress.threshold_n_connections = 75 |
Since 1.5.0.
This applies a child milter only when non-stressed.
Here is an example that spamass-milter isn't applied when stressed:
Example:
define_milter("spamass-milter") do |milter| milter.add_applicable_condition("No Stress") end
Since 1.5.0.
This notifies stressed to a child milter by "{stress}=yes" macro. This just notifies. It means that a child milter is always applied.
Here is an example that milter-greylist is notified stressed by macro.
Example:
define_milter("milter-greylist") do |milter| milter.add_applicable_condition("Stress Notify") end
Here is an example configuration for milter-greylist to use tarpitting on non-stress and greylisting on stress. This configuration requires milter-greylist 4.3.4 or later.
greylist.conf:
sm_macro "no_stress" "{stress}" unset racl whitelist sm_macro "no_stress" tarpit 125s racl greylist default
Since 1.6.0.
This sets "trusted_XXX=yes" macros for trusted session. Here is a list of macros:
Here is an example that you receive a SPF passed mail but apply greylist SPF not-passed mail for trusted domains:
milter-manager.local.conf:
define_milter("milter-greylist") do |milter| milter.add_applicable_condition("Trust") end
greylist.conf:
sm_macro "trusted_domain" "{trusted_domain}" "yes" racl whitelist sm_macro "trusted_domain" spf pass racl greylist sm_macro "trusted_domain" not spf pass
You can customize how to trust a session by the following configurations:
Since 1.6.0. This adds a trusted envelope-from domain. Here is a list of trusted domain by default:
Example: trust.add_envelope_from_domain("example.com") |
|
Since 1.8.0. This clears all registered trusted envelope-from domain list. Example: trust.clear |
|
Since 1.8.0.
This loads trusted envelope-from domain list from
# This is comment line. This line is ignored. gmail.com # The above line means 'gmail.com is trusted domain'. /\.example\.com/ # The above line means 'all sub domains of example.com are trusted'. # The above line consists of spaces. The space only line is ignored. Example: trust.load_envelope_from_domains("/etc/milter-manager/trusted-domains.list") # It loads trusted envelope-from domain list from # /etc/milter-manager/trusted-domains.list. |
This applies milters if recipients include envelope-recipient is matched the condition.
You need knowledge about Ruby from this section. Some useful applicable conditions are provided by default. You can define new applicable conditions if you need more conditions. You can decide which child milter is applied or not dynamically by defining our applicable conditions.
You define an applicable condition with the following syntax. You need knowledge about Ruby for defining applicable condition.
define_applicable_condition("NAME") do |condition| condition.description = ... condition.define_connect_stopper do |...| ... end ... end
For example, here is an applicable condition to implement S25R:
define_applicable_condition("S25R") do |condition| condition.description = "Selective SMTP Rejection" condition.define_connect_stopper do |context, host, socket_address| case host when "unknown", /\A\[.+\]\z/, /\A[^.]*\d[^\d.]+\d.*\./, /\A[^.]*\d{5}/, /\A(?:[^.]+\.)?\d[^.]*\.[^.]+\..+\.[a-z]/i, /\A[^.]*\d\.[^.]*\d-\d/, /\A[^.]*\d\.[^.]*\d\.[^.]+\..+\./, /\A(?:dhcp|dialup|ppp|[achrsvx]?dsl)[^.]*\d/i false else true end end end
'host' is "[IP ADDRESS]" not "unknown" when name resolution is failed. So, "unknown" is needless. It's sufficient that you just use /\A\[.+\]\z/. But it is included just in case. :-)
Here are configurable items in 'define_applicable_condition do ... end'.
There is no required item.
The object that has several information when you decide whether a child milter is applied or not. (The class of context is Milter::Manager::ChildContext.)
It has the following information.
Returns the name of child milter. It's name used when define_milter. Example: context.name # -> "clamav-milter" |
|
context[name] |
Returns value of available macro in the child milter In libmilter API, you need to surround macro name that has two or more length with "{}" but it isn't required. context[name] works well with/without "{}". Example: context["j"] # -> "mail.example.com" context["rcpt_address"] # -> "receiver@example.com" context["{rcpt_address}"] # -> "receiver@example.com" |
Returns true if the child milter returns 'reject'. The child milter must be enabled milter.evaluation_mode . Passed context should be always processing. So, context.reject? never return true. It's usuful when you use the other child milter's result. The other child can be retrieved by context.children[]. Example: context.reject? # -> false context.children["milter-greylist"].reject? # -> true or false |
|
Returns true if the child milter returns 'temporary failure'. The child milter must be enabled milter.evaluation_mode . Passed context should be always processing. So, context.temporay_failure? never return true. It's usuful when you use the other child milter's result. The other child can be retrieved by context.children[]. Example: context.temporary_failure? # -> false context.children["milter-greylist"].temporary_failure? # -> true or false |
|
Returns true if the child milter returns 'accept'. Passed context should be always processing. So, context.accept? never return true. It's usuful when you use the other child milter's result. The other child can be retrieved by context.children[]. Example: context.accept? # -> false context.children["milter-greylist"].accept? # -> true or false |
|
Returns true if the child milter returns 'discard'. The child milter must be enabled milter.evaluation_mode . Passed context should be always processing. So, context.discard? never return true. It's usuful when you use the other child milter's result. The other child can be retrieved by context.children[]. Example: context.discard? # -> false context.children["milter-greylist"].discard? # -> true or false |
|
Returns true if the child milter was quitted. Passed context should be always processing. So, context.quitted? never return true. It's usuful when you use the other child milter's result. The other child can be retrieved by context.children[]. Example: context.quitted? # -> false context.children["milter-greylist"].quitted? # -> true or false |
|
Returnes the other child milter's context. The name to refere the other child milter is a name that is used for define_milter. (i.e. the name returned by context.name) It returns nil if you refer with nonexistent name. Example: context.children["milter-greylist"] # -> milter-greylist's context context.children["nonexistent"] # -> nil context.children[context.name] # -> my context |
|
Returns true when MTA is Postfix. It is decided by "v" macro's value. If the value includes "Postfix", MTA will be Postfix. Returns true when MTA is Postfix, false otherwise. Example: context["v"] # -> "Postfix 2.5.5" context.postfix? # -> true context["v"] # -> "2.5.5" context.postfix? # -> false context["v"] # -> nil context.postfix? # -> false |
|
Returns true when sender is authenticated. It is decided by "auto_type" macro or "auth_authen" macro is available. They are available since MAIL FROM. So, it always returns false before MAIL FROM. You don't forget to add the following configuration to main.cf if you are using Postfix. milter_mail_macros = {auth_author} {auth_type} {auth_authen} It returns true when sender is authenticated, false otherwise. Example: context["auth_type"] # -> nil context["auth_authen"] # -> nil context.authenticated? # -> false context["auth_type"] # -> "CRAM-MD5" context["auth_authen"] # -> nil context.authenticated? # -> true context["auth_type"] # -> nil context["auth_authen"] # -> "sender" context.authenticated? # -> true |
|
Child milters can share data while mail transaction. Since 2.0.5 [Experimental] Example: define_applicable_condition("") do |condition| condition.define_envelope_recipient_stopper do |context, recipient| if /\Asomeone@example.com\z/ =~ recipient context.mail_transaction_shelf["stop-on-data"] = true end false end condition.define_data_stopper do |context| context.mail_transaction_shelf["stop-on-data"] end end |
The object that describes socket address. Socket is one of IPv4 socket, IPv6 socket and UNIX domain socket. Socket address is described as corresponding object.
It describes IPv4 socket address. It has the following methods.
Returns dot-notation IPv4 address. Example: socket_address.address # -> "192.168.1.1" |
|
Returns port number. Example: socket_address.port # -> 12345 |
|
Returns IPv4 address formated as connection_spec format. Example: socket_address.to_s # -> "inet:12345@[192.168.1.1]" |
|
Returns true if the address is private network address, false otherwise. Example: socket_address.to_s # -> "inet:12345@[127.0.0.1]" socket_address.local? # -> true socket_address.to_s # -> "inet:12345@[192.168.1.1]" socket_address.local? # -> true socket_address.to_s # -> "inet:12345@[160.XXX.XXX.XXX]" socket_address.local? # -> false |
|
Returnes corresponding IPAddr object. Example: socket_address.to_s # -> "inet:12345@[127.0.0.1]" socket_address.to_ip_address # -> #<IPAddr: IPv4:127.0.0.1/255.255.255.255> |
It describes IPv6 socket address. It has the following methods.
address |
Returns colon-notation IPv6 address. Example: socket_address.address # -> "::1" |
port |
Returns port number. Example: socket_address.port # -> 12345 |
to_s |
Returns IPv6 address formated as connection_spec format. Example: socket_address.to_s # -> "inet6:12345@[::1]" |
local? |
Returns true if the address is private network address, false otherwise. Example: socket_address.to_s # -> "inet6:12345@[::1]" socket_address.local? # -> true socket_address.to_s # -> "inet6:12345@[fe80::XXXX]" socket_address.local? # -> true socket_address.to_s # -> "inet6:12345@[2001::XXXX]" socket_address.local? # -> false |
to_ip_address |
Returnes corresponding IPAddr object. Example: socket_address.to_s # -> "inet6:12345@[::1]" socket_address.to_ip_address # -> #<IPAddr: IPv6:0000:0000:0000:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff> |
It describes UNIX domain ssocket address. It has the following methods.
Returns path of the socket. Example: socket_address.path # -> "/tmp/local.sock" |
|
to_s |
Returns UNIX domain socket address formated as connection_spec format. Exampel: socket_address.to_s # -> "unix:/tmp/local.sock" |
local? |
Always returns true. Example: socket_address.local? # -> true |
to_ip_address |
Always returnes nil. Example: socket_address.to_s # -> "unix:/tmp/local.sock" socket_address.to_ip_address # -> nil |
Since 1.6.6.
You need knowledge about Ruby for this section. Milter manager supports ActiveRecord as database operation library. You can use many RDB like MySQL, SQLite3 and so on because ActiveRecord supports them.
You need to install ActiveRecord to use database. See optional install documents for ActiveRecord install.
Let's start small example for using 'users' table in MySQL.
Here is connection information for MySQL server:
mail-system |
|
192.168.0.1 |
|
milter-manager |
|
secret |
First, you write the above connection information to milter-manager.local.conf. In this example, milter-manager.local.conf is placed at /etc/milter-manager/milter-manager.local.conf.
/etc/milter-manager/milter-manager.local.conf:
database.type = "mysql2" database.name = "mail-system" database.host = "192.168.0.1" database.user = "milter-manager" database.password = "secret"
Next, you define ActiveRecord object to operate 'users' table. Definition files are placed at models/ directory. models/ directory is placed at the same directory of milter-manager.local.conf. You create models/user.rb.
/etc/milter-manager/models/user.rb:
class User < ActiveRecord::Base end
Last, you connect to database and operate data in milter-manager.local.conf:
/etc/milter-manager/milter-manager.local.conf:
database.setup database.load_models("models/*.rb") User.all.each do |user| p user.name # => "alice", "bob", ... end
Here are completed files:
/etc/milter-manager/milter-manager.local.conf:
# Configure connection information database.type = "mysql2" database.name = "mail-system" database.host = "192.168.0.1" database.user = "milter-manager" database.password = "secret" # Connect database.setup # Load definitions database.load_models("models/*.rb") # Operate data User.all.each do |user| p user.name # => "alice", "bob", ... end
/etc/milter-manager/models/user.rb:
class User < ActiveRecord::Base end
Here are configuration items:
Specifies a database type. Here are available types:
Example: database.type = "mysql2" # uses MySQL |
|||||||
Specifies database name.
For SQLite3, it specifies database path or
Example: database.name = "configurations" # connects 'configurations' database |
|||||||
Specifies database server host name. In MySQL and so on, "localhost" is used as the default value. In SQLite3, it is ignored. Example: database.host = "192.168.0.1" # connects to server running at 192.168.0.1 |
|||||||
Specifies database server port number. In many cases, you don't need to specify this value explicitly. Because an applicable default value is used. In SQLite3, it is ignored. Example: database.port = 3306 # connects to server running at3 3306 port. |
|||||||
Specifies database server UNIX domain socket path. In SQLite3, it is used as database path. But .#database.name is prioritize over this. It's recommended that .#database.name is used rather than .#database.path . Example: database.path = "/var/run/mysqld/mysqld.sock" # connects to MySQL via UNIX domain socket |
|||||||
Specifies database user on connect. In SQLite3, it is ignored. Example: database.user = "milter-manager" # connects to server as 'milter-manager' user |
|||||||
Specifies database password on connect. In SQLite3, it is ignored. Example: database.password = "secret" |
|||||||
Since 1.6.9.
Specifies extra options. Here is an example to specify
database.type = "mysql2" database.extra_options[:reconnect] = true Available extra options are different for each database. Example: database.extra_options[:reconnect] = true |
|||||||
Connects to database. You connect to database at this time. After this, you can operate data. Example: database.setup |
|||||||
Loads Ruby scripts that write class definitions for ActiveRecord. You can use glob for
Example: # Loads # /etc/milter-manager/models/user.rb # /etc/milter-manager/models/group.rb # /etc/milter-manager/models/... # (In /etc/milter-manager/milter-manager.conf case.) database.load_models("models/*.rb") |