diff --git a/docs/man/maddy-auth.5.scd b/docs/man/maddy-auth.5.scd
index 7bc8505..f38584c 100644
--- a/docs/man/maddy-auth.5.scd
+++ b/docs/man/maddy-auth.5.scd
@@ -16,7 +16,7 @@ that contains all usernames known to the module. Exceptions are extauth and
pam as underlying interfaces do not define a way to check credentials
existence.
-# External authentication module (extauth)
+# External authentication module (auth.external)
Module for authentication using external helper binary. It looks for binary
named maddy-auth-helper in $PATH and libexecdir and uses it for authentication
@@ -30,7 +30,7 @@ authentication is failed. If the status code is 2 - another unrelated error has
happened. Additional information should be written to stderr.
```
-extauth {
+auth.external {
helper /usr/bin/ldap-helper
perdomain no
domains example.org
@@ -63,7 +63,7 @@ If used without 'perdomain', domain part will be removed from login before
check with underlying auth. mechanism. If 'perdomain' is set, then
domains must be also set and domain part WILL NOT be removed before check.
-# PAM module (pam)
+# PAM module (auth.pam)
Implements authentication using libpam. Alternatively it can be configured to
use helper binary like extauth module does.
@@ -75,7 +75,7 @@ go get -tags 'libpam' ...
```
```
-pam {
+auth.pam {
debug no
use_helper no
}
@@ -107,13 +107,13 @@ chown root:maddy /usr/lib/maddy/maddy-pam-helper
chmod u+xs,g+x,o-x /usr/lib/maddy/maddy-pam-helper
```
-# Shadow database authentication module (shadow)
+# Shadow database authentication module (auth.shadow)
Implements authentication by reading /etc/shadow. Alternatively it can be
configured to use helper binary like extauth does.
```
-shadow {
+auth.shadow {
debug no
use_helper no
}
@@ -143,7 +143,7 @@ chown root:maddy /usr/lib/maddy/maddy-shadow-helper
chmod u+xs,g+x,o-x /usr/lib/maddy/maddy-shadow-helper
```
-# Table-based password hash lookup (pass_table)
+# Table-based password hash lookup (auth.pass_table)
This module implements username:password authentication by looking up the
password hash using a table module (maddy-tables(5)). It can be used
@@ -153,7 +153,7 @@ to load user credentials from text file (file module) or SQL query
Definition:
```
-pass_table [block name] {
+auth.pass_table [block name] {
table
}
@@ -188,14 +188,14 @@ the 'maddyctl creds' command can be used to modify the underlying tables
via pass_table module. It will act a "local credentials store" and will write
appropriate hash values to the table.
-# Separate username and password lookup (plain_separate)
+# Separate username and password lookup (auth.plain_separate)
This module implements authentication using username:password pairs but can
use zero or more "table modules" (maddy-tables(5)) and one or more
authentication providers to verify credentials.
```
-plain_separate {
+auth.plain_separate {
user ...
user ...
...
@@ -231,7 +231,7 @@ Configuration block for any auth. provider module can be used here, even
The used auth. provider must provide username:password pair-based
authentication.
-# Dovecot authentication client (dovecot_sasl)
+# Dovecot authentication client (auth.dovecot_sasl)
The 'dovecot_sasl' module implements the client side of the Dovecot
authentication protocol, allowing maddy to use it as a credentials source.
@@ -240,7 +240,7 @@ Currently SASL mechanisms support is limited to mechanisms supported by maddy
so you cannot get e.g. SCRAM-MD5 this way.
```
-dovecot_sasl {
+auth.dovecot_sasl {
endpoint unix://socket_path
}
diff --git a/docs/man/maddy-filters.5.scd b/docs/man/maddy-filters.5.scd
index f9e6676..056af7f 100644
--- a/docs/man/maddy-filters.5.scd
+++ b/docs/man/maddy-filters.5.scd
@@ -87,13 +87,13 @@ the STARTTLS command.
By default, rejects messages coming from unencrypted servers. Use the
'fail_action' directive to change that.
-# DKIM authentication module (verify_dkim)
+# DKIM authentication module (check.dkim)
This is the check module that performs verification of the DKIM signatures
present on the incoming messages.
```
-verify_dkim {
+check.dkim {
debug no
required_fields From Subject
allow_body_subset no
@@ -152,13 +152,13 @@ Whether to accept the message if a temporary error occurs during DKIM
verification. Rejecting the message with a 4xx code will require the sender
to resend it later in a hope that the problem will be resolved.
-# SPF policy enforcement module (apply_spf)
+# SPF policy enforcement module (check.spf)
This is the check module that verifies whether IP address of the client is
authorized to send messages for domain in MAIL FROM address.
```
-apply_spf {
+check.spf {
debug no
enforce_early no
fail_action quarantine
@@ -173,7 +173,7 @@ apply_spf {
It is recommended by the DMARC standard to don't fail delivery based solely on
SPF policy and always check DMARC policy and take action based on it.
-If enforce_early is no, apply_spf module will not take any action on SPF
+If enforce_early is no, check.spf module will not take any action on SPF
policy failure if sender domain does have a DMARC record with 'quarantine' or
'reject' policy. Instead it will rely on DMARC support to take necesary
actions using SPF results as an input.
@@ -186,7 +186,7 @@ no-op and is considered insecure.
*Syntax*: debug _boolean_ ++
*Default*: global directive value
-Enable verbose logging for apply_spf.
+Enable verbose logging for check.spf.
*Syntax*: enforce_early _boolean_ ++
*Default*: no
@@ -230,7 +230,7 @@ Action to take when SPF policy evaluates to a 'permerror' result.
Action to take when SPF policy evaluates to a 'temperror' result.
-# DNSBL lookup module (dnsbl)
+# DNSBL lookup module (check.dnsbl)
The dnsbl module implements checking of source IP and hostnames against a set
of DNS-based Blackhole lists (DNSBLs).
@@ -239,7 +239,7 @@ Its configuration consists of module configuration directives and a set
of blocks specifing lists to use and kind of lookups to perform on them.
```
-dnsbl {
+check.dnsbl {
debug no
check_early no
@@ -387,13 +387,13 @@ will be rejected.
It is possible to specify a negative value to make list act like a whitelist
and override results of other blocklists.
-# DKIM signing module (sign_dkim)
+# DKIM signing module (modify.dkim)
sign_dkim module is a modifier that signs messages using DKIM
protocol (RFC 6376).
```
-sign_dkim {
+modify.dkim {
debug no
domains example.org example.com
selector default
@@ -414,7 +414,7 @@ domains and selector can be specified in arguments, so actual sign_dkim use can
be shortened to the following:
```
modify {
- sign_dkim example.org selector
+ dkim example.org selector
}
```
@@ -574,7 +574,7 @@ Sign emails from subdomains using a top domain key.
Allows only one domain to be specified (can be workarounded using sign_dkim
multiple times).
-# Envelope sender / recipient rewriting (replace_sender, replace_rcpt)
+# Envelope sender / recipient rewriting (modify.replace_sender, modify.replace_rcpt)
'replace_sender' and 'replace_rcpt' modules replace SMTP envelope addresses
based on the mapping defined by the table module (maddy-tables(5)). Currently,
@@ -625,7 +625,7 @@ cat: dog
cat@example.org: cat@example.com
```
-# System command filter (command)
+# System command filter (check.command)
This module executes an arbitrary system command during a specified stage of
checks execution.
@@ -756,7 +756,7 @@ Two codes are defined implicitly, exit code 1 causes the message to be rejected
with a permanent error, exit code 2 causes the message to be quarantined. Both
action can be overriden using the 'code' directive.
-## Milter protocol check (milter)
+## Milter protocol check (check.milter)
The 'milter' implements subset of Sendmail's milter protocol that can be used
to integrate external software in maddy.
@@ -773,7 +773,7 @@ removed without major changes to it. Restrictions 3, 4 and 5 are temporary due t
incomplete implementation.
```
-milter {
+check.milter {
endpoint
fail_open false
}
@@ -801,13 +801,13 @@ The endpoit is specified in standard URL-like format:
Toggles behavior on milter I/O errors. If false ("fail closed") - message is
rejected with temporary error code. If true ("fail open") - check is skipped.
-## rspamd check (rspamd)
+## rspamd check (check.rspamd)
The 'rspamd' module implements message filtering by contacting the rspamd
server via HTTP API.
```
-rspamd {
+check.rspamd {
tls_client { ... }
api_path http://127.0.0.1:11333
settings_id whatever
diff --git a/docs/man/maddy-smtp.5.scd b/docs/man/maddy-smtp.5.scd
index 05a4146..8e13cd7 100644
--- a/docs/man/maddy-smtp.5.scd
+++ b/docs/man/maddy-smtp.5.scd
@@ -147,7 +147,7 @@ check module.
*NOTE*: Report generation is not implemented now.
-*NOTE*: DMARC needs apply_spf and verify_dkim checks to function correctly.
+*NOTE*: DMARC needs SPF and DKIM checks to function correctly.
Without these, DMARC check will not run.
## Rate & concurrency limiting
@@ -538,8 +538,8 @@ This configuration allows to specify alias local addresses to remote ones
without being an open relay, since remote_queue can be used only if remote
address was introduced as a result of rewrite of local address.
-*WARNING*: If you have DMARC enabled (default), results generated by apply_spf
-and verify_dkim checks inside a reroute block *will not* be considered in DMARC
+*WARNING*: If you have DMARC enabled (default), results generated by SPF
+and DKIM checks inside a reroute block *will not* be considered in DMARC
evaluation.
*Syntax*: destination_in _table reference_ { ... } ++
@@ -553,7 +553,7 @@ Takes precedence over all 'destination' directives.
Example:
```
destination_in file /etc/maddy/remote_addrs {
- deliver_to smtp_downstream tcp://10.0.0.7:25
+ deliver_to smtp tcp://10.0.0.7:25
}
destination example.com {
deliver_to &local_mailboxes
@@ -575,7 +575,7 @@ destination_in sql_table {
In this case, configuration should be specified separately and be referneced
using '&' syntax:
```
-sql_table remote_addrs {
+table.sql_table remote_addrs {
dsn ...
driver ...
}
diff --git a/docs/man/maddy-storage.5.scd b/docs/man/maddy-storage.5.scd
index e6d6f2b..3b78b27 100644
--- a/docs/man/maddy-storage.5.scd
+++ b/docs/man/maddy-storage.5.scd
@@ -19,7 +19,7 @@ auto-creation will not happen when delivering incoming messages via SMTP as
there is no authentication to confirm that this account should indeed be
created.
-# SQL-based database module (imapsql)
+# SQL-based database module (storage.imapsql)
The imapsql module implements unified database for IMAP index and message
metadata using SQL-based relational database.
@@ -37,7 +37,7 @@ case-insensitive. UTF-8 names are supported with restrictions defined in the
PRECIS UsernameCaseMapped profile.
```
-imapsql {
+storage.imapsql {
driver sqlite3
dsn imapsql.db
}
diff --git a/docs/man/maddy-tables.5.scd b/docs/man/maddy-tables.5.scd
index b1ea0fc..33d2568 100644
--- a/docs/man/maddy-tables.5.scd
+++ b/docs/man/maddy-tables.5.scd
@@ -11,7 +11,7 @@ change the source of data, effectively turning the table into a complete
interface to a key-value store for maddy. Such tables are referred to as
"mutable tables".
-# File mapping (file)
+# File mapping (table.file)
This module builds string-string mapping from a text file.
@@ -58,13 +58,13 @@ aaa: bbb
aaa
```
-# SQL query mapping (sql_query)
+# SQL query mapping (table.sql_query)
The sql_query module implements table interface using SQL queries.
Definition:
```
-sql_query {
+table.sql_query {
driver
dsn
lookup
@@ -125,7 +125,7 @@ List of queries to execute on initialization. Can be used to configure RDBMS.
Example, to improve SQLite3 performance:
```
-sql_query {
+table.sql_query {
driver sqlite3
dsn whatever.db
init "PRAGMA journal_mode=WAL" \
@@ -155,13 +155,13 @@ entry in the database.
'del' query gets :key argument - key and should remove it from the database.
-# Static table (static)
+# Static table (table.static)
The 'static' module implements table lookups using key-value pairs in its
configuration.
```
-static {
+table.static {
entry KEY1 VALUE1
entry KEY2 VALUE2
...
@@ -176,7 +176,7 @@ Add an entry to the table.
If the same key is used multiple times, the last one takes effect.
-# Regexp rewrite table (regexp)
+# Regexp rewrite table (table.regexp)
The 'regexp' module implements table lookups by applying a regular expression
to the key value. If it matches - 'replacement' value is returned with $N
@@ -187,7 +187,7 @@ The regular expression syntax is the subset of PCRE. See
https://golang.org/pkg/regexp/syntax/ for details.
```
-regexp {
+table.regexp {
full_match yes
case_insensitive yes
expand_placeholders yes
@@ -216,12 +216,12 @@ corresponding capture groups from the match.
To insert a literal $ in the output, use $$ in the template.
-# Identity table (identity)
+# Identity table (table.identity)
The module 'identity' is a table module that just returns the key looked up.
```
-identity { }
+table.identity { }
```
# No-op table (dummy)
diff --git a/docs/man/maddy-targets.5.scd b/docs/man/maddy-targets.5.scd
index dfc1caf..66c4204 100644
--- a/docs/man/maddy-targets.5.scd
+++ b/docs/man/maddy-targets.5.scd
@@ -5,18 +5,18 @@ maddy-targets(5) "maddy mail server" "maddy reference documentation"
This man page describes modules that can used with 'deliver_to' directive
of SMTP endpoint module.
-# SQL module (sql)
+# SQL module (target.imapsql)
SQL module described in *maddy-storage*(5) can also be used as a delivery
target.
-# Queue module (queue)
+# Queue module (target.queue)
Queue module buffers messages on disk and retries delivery multiple times to
another target to ensure reliable delivery.
```
-queue {
+target.queue {
target remote
location ...
max_parallelism 16
@@ -98,7 +98,7 @@ Module that implements message delivery to remote MTAs discovered via DNS MX
records. You probably want to use it with queue module for reliability.
```
-remote {
+target.remote {
hostname mx.example.org
debug no
}
@@ -344,21 +344,21 @@ Set the minimal MX security level required for all outbound messages.
See [Security levels](../../seclevels) page for details.
-# SMTP transparent forwarding module (smtp_downstream)
+# SMTP transparent forwarding module (target.smtp)
Module that implements transparent forwarding of messages over SMTP.
Use in pipeline configuration:
```
-deliver_to smtp_downstream tcp://127.0.0.1:5353
+deliver_to smtp tcp://127.0.0.1:5353
# or
-deliver_to smtp_downstream tcp://127.0.0.1:5353 {
+deliver_to smtp tcp://127.0.0.1:5353 {
# Other settings, see below.
}
```
```
-smtp_downstream {
+target.smtp {
debug no
tls_client {
...
@@ -439,7 +439,7 @@ TLS).
Multiple addresses can be specified, they will be tried in order until connection to
one succeeds (including TLS handshake if TLS is required).
-# LMTP transparent forwarding module (lmtp_downstream)
+# LMTP transparent forwarding module (target.lmtp)
-The 'lmtp_downstream' module is similar to 'smtp_downstream' and supports all
+The 'target.lmtp' module is similar to 'target.smtp' and supports all
its options and syntax but speaks LMTP instead of SMTP.
diff --git a/docs/man/maddy.1.scd b/docs/man/maddy.1.scd
index cabd5c4..10b5038 100644
--- a/docs/man/maddy.1.scd
+++ b/docs/man/maddy.1.scd
@@ -61,9 +61,9 @@ smtp ... {
# Deliver messages to the 'dummy' module with the default configuration.
deliver_to dummy
- # Deliver messages to the 'smtp_downstream' module with
+ # Deliver messages to the 'target.smtp' module with
# 'tcp://127.0.0.1:1125' argument as a configuration.
- deliver_to smtp_downstream tcp://127.0.0.1:1125
+ deliver_to smtp tcp://127.0.0.1:1125
# Deliver messages to the 'queue' module with the specified configuration.
deliver_to queue {
@@ -78,7 +78,7 @@ at the top-level and merely referenced by its name where it is needed.
Here is the example:
```
-sql local_mailboxes {
+storage.imapsql local_mailboxes {
driver sqlite3
dsn all.db
}
@@ -93,18 +93,24 @@ initialize such as storage backends and authentication providers.
For top-level configuration block definition, syntax is as follows:
```
-module_name config_block_name... {
+namespace.module_name config_block_name... {
module_configuration
}
```
If config_block_name is omitted, it will be the same as module_name. Multiple
names can be specified. All names must be unique.
+Note the "storage." prefix. The actual module name is this and includes
+"namespace". It is a little cheating to make more concise names and can
+be omitted when you reference the module where it is used since it can
+be implied (e.g. putting module reference in "check{}" likely means you want
+something with "check." prefix)
+
Usual module arguments can't be specified when using this syntax, however,
modules usually provide explicit directives that allow to specify the needed
values. For example 'sql sqlite3 all.db' is equivalent to
```
-sql {
+storage.imapsql {
driver sqlite3
dsn all.db
}
diff --git a/docs/tutorials/smtp-only.md b/docs/tutorials/smtp-only.md
index ea3b37b..b115428 100644
--- a/docs/tutorials/smtp-only.md
+++ b/docs/tutorials/smtp-only.md
@@ -29,9 +29,9 @@ service lmtp {
}
```
-Add `local_mailboxes` block to maddy config using `lmtp_downstream` module:
+Add `local_mailboxes` block to maddy config using `target.lmtp` module:
```
-lmtp_downstream local_mailboxes {
+target.lmtp local_mailboxes {
targets unix:///var/run/maddy/dovecot-lmtp.sock
}
```
diff --git a/internal/README.md b/internal/README.md
index 1d1fb0c..882eed4 100644
--- a/internal/README.md
+++ b/internal/README.md
@@ -12,7 +12,7 @@ endpoint/
modules - protocol listeners (e.g. SMTP server, etc)
target/
modules - final delivery targets (including outbound delivery, such as
- smtp_downstream, remote)
+ target.smtp, remote)
auth/
modules - authentication providers
check/
diff --git a/internal/auth/external/externalauth.go b/internal/auth/external/externalauth.go
index e7002a0..e2c096d 100644
--- a/internal/auth/external/externalauth.go
+++ b/internal/auth/external/externalauth.go
@@ -81,5 +81,6 @@ func (ea *ExternalAuth) AuthPlain(username, password string) error {
}
func init() {
- module.Register("extauth", NewExternalAuth)
+ module.RegisterDeprecated("extauth", "auth.command", NewExternalAuth)
+ module.Register("auth.external", NewExternalAuth)
}
diff --git a/internal/auth/pam/module.go b/internal/auth/pam/module.go
index c31b821..0aa9684 100644
--- a/internal/auth/pam/module.go
+++ b/internal/auth/pam/module.go
@@ -72,5 +72,6 @@ func (a *Auth) AuthPlain(username, password string) error {
}
func init() {
- module.Register("pam", New)
+ module.RegisterDeprecated("pam", "auth.pam", New)
+ module.Register("auth.pam", New)
}
diff --git a/internal/auth/pass_table/table.go b/internal/auth/pass_table/table.go
index b696e6c..db9736a 100644
--- a/internal/auth/pass_table/table.go
+++ b/internal/auth/pass_table/table.go
@@ -29,7 +29,7 @@ func New(modName, instName string, _, inlineArgs []string) (module.Module, error
func (a *Auth) Init(cfg *config.Map) error {
if len(a.inlineArgs) != 0 {
- return modconfig.ModuleFromNode(a.inlineArgs, cfg.Block, cfg.Globals, &a.table)
+ return modconfig.ModuleFromNode("table", a.inlineArgs, cfg.Block, cfg.Globals, &a.table)
}
cfg.Custom("table", false, true, nil, modconfig.TableDirective, &a.table)
@@ -168,5 +168,6 @@ func (a *Auth) DeleteUser(username string) error {
}
func init() {
- module.Register("pass_table", New)
+ module.RegisterDeprecated("pass_table", "auth.pass_table", New)
+ module.Register("auth.pass_table", New)
}
diff --git a/internal/auth/plain_separate/plain_separate.go b/internal/auth/plain_separate/plain_separate.go
index 90e4213..adec3c3 100644
--- a/internal/auth/plain_separate/plain_separate.go
+++ b/internal/auth/plain_separate/plain_separate.go
@@ -101,5 +101,6 @@ func (a *Auth) AuthPlain(username, password string) error {
}
func init() {
- module.Register("plain_separate", NewAuth)
+ module.RegisterDeprecated("plain_separate", "auth.plain_separate", NewAuth)
+ module.Register("auth.plain_separate", NewAuth)
}
diff --git a/internal/auth/sasl.go b/internal/auth/sasl.go
index 4377fd2..63cf2de 100644
--- a/internal/auth/sasl.go
+++ b/internal/auth/sasl.go
@@ -93,7 +93,7 @@ func (s *SASLAuth) CreateSASL(mech string, remoteAddr net.Addr, successCb func(i
// the 'auth' configuration directive.
func (s *SASLAuth) AddProvider(m *config.Map, node config.Node) error {
var any interface{}
- if err := modconfig.ModuleFromNode(node.Args, node, m.Globals, &any); err != nil {
+ if err := modconfig.ModuleFromNode("auth", node.Args, node, m.Globals, &any); err != nil {
return err
}
diff --git a/internal/auth/shadow/module.go b/internal/auth/shadow/module.go
index 30614bf..ec0d179 100644
--- a/internal/auth/shadow/module.go
+++ b/internal/auth/shadow/module.go
@@ -112,5 +112,6 @@ func (a *Auth) AuthPlain(username, password string) error {
}
func init() {
- module.Register("shadow", New)
+ module.RegisterDeprecated("shadow", "auth.shadow", New)
+ module.Register("auth.shadow", New)
}
diff --git a/internal/check/command/command.go b/internal/check/command/command.go
index 7eadd5a..45a98a2 100644
--- a/internal/check/command/command.go
+++ b/internal/check/command/command.go
@@ -25,7 +25,7 @@ import (
"github.com/foxcpp/maddy/internal/target"
)
-const modName = "command"
+const modName = "check.command"
type Stage string
@@ -379,5 +379,6 @@ func (s *state) Close() error {
}
func init() {
+ module.RegisterDeprecated("command", "check.command", New)
module.Register(modName, New)
}
diff --git a/internal/check/dkim/dkim.go b/internal/check/dkim/dkim.go
index 44a8d9b..a10438a 100644
--- a/internal/check/dkim/dkim.go
+++ b/internal/check/dkim/dkim.go
@@ -257,5 +257,6 @@ func (c *Check) CheckStateForMsg(ctx context.Context, msgMeta *module.MsgMetadat
}
func init() {
- module.Register("verify_dkim", New)
+ module.RegisterDeprecated("verify_dkim", "check.dkim", New)
+ module.Register("check.dkim", New)
}
diff --git a/internal/check/dnsbl/dnsbl.go b/internal/check/dnsbl/dnsbl.go
index 97a3f95..3bfc8bb 100644
--- a/internal/check/dnsbl/dnsbl.go
+++ b/internal/check/dnsbl/dnsbl.go
@@ -423,5 +423,6 @@ func (*state) Close() error {
}
func init() {
- module.Register("dnsbl", NewDNSBL)
+ module.RegisterDeprecated("dnsbl", "check.dnsbl", NewDNSBL)
+ module.Register("check.dnsbl", NewDNSBL)
}
diff --git a/internal/check/milter/milter.go b/internal/check/milter/milter.go
index 7eaf103..342e308 100644
--- a/internal/check/milter/milter.go
+++ b/internal/check/milter/milter.go
@@ -18,7 +18,7 @@ import (
"github.com/foxcpp/maddy/internal/target"
)
-const modName = "milter"
+const modName = "check.milter"
type Check struct {
cl *milter.Client
@@ -408,5 +408,6 @@ func (s *state) Close() error {
}
func init() {
+ module.RegisterDeprecated("milter", "check.milter", New)
module.Register(modName, New)
}
diff --git a/internal/check/rspamd/rspamd.go b/internal/check/rspamd/rspamd.go
index b04b455..9ba7101 100644
--- a/internal/check/rspamd/rspamd.go
+++ b/internal/check/rspamd/rspamd.go
@@ -20,7 +20,7 @@ import (
"github.com/foxcpp/maddy/internal/target"
)
-const modName = "rspamd"
+const modName = "check.rspamd"
type Check struct {
instName string
@@ -332,5 +332,6 @@ func (s *state) Close() error {
}
func init() {
+ module.RegisterDeprecated("rspamd", modName, New)
module.Register(modName, New)
}
diff --git a/internal/check/spf/spf.go b/internal/check/spf/spf.go
index 0ae15c3..9453c30 100644
--- a/internal/check/spf/spf.go
+++ b/internal/check/spf/spf.go
@@ -25,7 +25,7 @@ import (
"golang.org/x/net/idna"
)
-const modName = "apply_spf"
+const modName = "check.spf"
type Check struct {
instName string
@@ -371,5 +371,6 @@ func (s *state) Close() error {
}
func init() {
+ module.RegisterDeprecated("apply_spf", "check.spf", New)
module.Register(modName, New)
}
diff --git a/internal/config/module/interfaces.go b/internal/config/module/interfaces.go
index 0883dca..323ad3a 100644
--- a/internal/config/module/interfaces.go
+++ b/internal/config/module/interfaces.go
@@ -7,7 +7,7 @@ import (
func MessageCheck(globals map[string]interface{}, args []string, block config.Node) (module.Check, error) {
var check module.Check
- if err := ModuleFromNode(args, block, globals, &check); err != nil {
+ if err := ModuleFromNode("check", args, block, globals, &check); err != nil {
return nil, err
}
return check, nil
@@ -29,7 +29,7 @@ func DeliveryDirective(m *config.Map, node config.Node) (interface{}, error) {
func DeliveryTarget(globals map[string]interface{}, args []string, block config.Node) (module.DeliveryTarget, error) {
var target module.DeliveryTarget
- if err := ModuleFromNode(args, block, globals, &target); err != nil {
+ if err := ModuleFromNode("target", args, block, globals, &target); err != nil {
return nil, err
}
return target, nil
@@ -37,7 +37,7 @@ func DeliveryTarget(globals map[string]interface{}, args []string, block config.
func MsgModifier(globals map[string]interface{}, args []string, block config.Node) (module.Modifier, error) {
var check module.Modifier
- if err := ModuleFromNode(args, block, globals, &check); err != nil {
+ if err := ModuleFromNode("modify", args, block, globals, &check); err != nil {
return nil, err
}
return check, nil
@@ -45,7 +45,7 @@ func MsgModifier(globals map[string]interface{}, args []string, block config.Nod
func StorageDirective(m *config.Map, node config.Node) (interface{}, error) {
var backend module.Storage
- if err := ModuleFromNode(node.Args, node, m.Globals, &backend); err != nil {
+ if err := ModuleFromNode("storage", node.Args, node, m.Globals, &backend); err != nil {
return nil, err
}
return backend, nil
@@ -53,7 +53,7 @@ func StorageDirective(m *config.Map, node config.Node) (interface{}, error) {
func TableDirective(m *config.Map, node config.Node) (interface{}, error) {
var tbl module.Table
- if err := ModuleFromNode(node.Args, node, m.Globals, &tbl); err != nil {
+ if err := ModuleFromNode("table", node.Args, node, m.Globals, &tbl); err != nil {
return nil, err
}
return tbl, nil
diff --git a/internal/config/module/modconfig.go b/internal/config/module/modconfig.go
index c93e990..5b5cd2c 100644
--- a/internal/config/module/modconfig.go
+++ b/internal/config/module/modconfig.go
@@ -22,10 +22,23 @@ import (
)
// createInlineModule is a helper function for config matchers that can create inline modules.
-func createInlineModule(modName string, args []string) (module.Module, error) {
- newMod := module.Get(modName)
+func createInlineModule(preferredNamespace string, modName string, args []string) (module.Module, error) {
+ var newMod module.FuncNewModule
+
+ // First try to extend the name with preferred namespace unless the name
+ // already contains it.
+ if !strings.Contains(modName, ".") && preferredNamespace != "" {
+ newMod = module.Get(preferredNamespace + "." + modName)
+ }
+
+ // Then try global namespace for compatibility and complex modules.
if newMod == nil {
- return nil, fmt.Errorf("unknown module: %s", modName)
+ newMod = module.Get(modName)
+ }
+
+ // Bail if both failed.
+ if newMod == nil {
+ return nil, fmt.Errorf("unknown module: %s (namespace: %s)", modName, preferredNamespace)
}
return newMod(modName, "", nil, args)
@@ -67,7 +80,11 @@ func initInlineModule(modObj module.Module, globals map[string]interface{}, bloc
// pointer (e.g. it implements all necessary interfaces) and stores it if everything is fine.
// If module object doesn't implement necessary module interfaces - error is returned.
// If modObj is not a pointer, ModuleFromNode panics.
-func ModuleFromNode(args []string, inlineCfg config.Node, globals map[string]interface{}, moduleIface interface{}) error {
+//
+// preferredNamespace is used as an implicit prefix for module name lookups.
+// Module with name preferredNamespace + "." + args[0] will be preferred over just args[0].
+// It can be omitted.
+func ModuleFromNode(preferredNamespace string, args []string, inlineCfg config.Node, globals map[string]interface{}, moduleIface interface{}) error {
if len(args) == 0 {
return parser.NodeErr(inlineCfg, "at least one argument is required")
}
@@ -84,7 +101,7 @@ func ModuleFromNode(args []string, inlineCfg config.Node, globals map[string]int
log.Debugf("%s:%d: reference %s", inlineCfg.File, inlineCfg.Line, args[0])
} else {
log.Debugf("%s:%d: new module %s %v", inlineCfg.File, inlineCfg.Line, args[0], args[1:])
- modObj, err = createInlineModule(args[0], args[1:])
+ modObj, err = createInlineModule(preferredNamespace, args[0], args[1:])
}
if err != nil {
return err
@@ -122,5 +139,5 @@ func GroupFromNode(defaultModule string, args []string, inlineCfg config.Node, g
if len(args) == 0 {
args = append(args, defaultModule)
}
- return ModuleFromNode(args, inlineCfg, globals, moduleIface)
+ return ModuleFromNode("", args, inlineCfg, globals, moduleIface)
}
diff --git a/internal/modify/dkim/dkim.go b/internal/modify/dkim/dkim.go
index 2379770..be9f7e6 100644
--- a/internal/modify/dkim/dkim.go
+++ b/internal/modify/dkim/dkim.go
@@ -365,5 +365,6 @@ func (s state) Close() error {
}
func init() {
- module.Register("sign_dkim", New)
+ module.RegisterDeprecated("sign_dkim", "modify.dkim", New)
+ module.Register("modify.dkim", New)
}
diff --git a/internal/modify/replace_addr.go b/internal/modify/replace_addr.go
index 4031f75..cb857e7 100644
--- a/internal/modify/replace_addr.go
+++ b/internal/modify/replace_addr.go
@@ -41,7 +41,7 @@ func NewReplaceAddr(modName, instName string, _, inlineArgs []string) (module.Mo
}
func (r *replaceAddr) Init(cfg *config.Map) error {
- return modconfig.ModuleFromNode(r.inlineArgs, cfg.Block, cfg.Globals, &r.table)
+ return modconfig.ModuleFromNode("table", r.inlineArgs, cfg.Block, cfg.Globals, &r.table)
}
func (r replaceAddr) Name() string {
@@ -122,6 +122,8 @@ func (r replaceAddr) rewrite(val string) (string, error) {
}
func init() {
- module.Register("replace_sender", NewReplaceAddr)
- module.Register("replace_rcpt", NewReplaceAddr)
+ module.Register("modify.replace_sender", NewReplaceAddr)
+ module.RegisterDeprecated("replace_sender", "modify.replace_sender", NewReplaceAddr)
+ module.Register("modify.replace_rcpt", NewReplaceAddr)
+ module.RegisterDeprecated("replace_rcpt", "modify.replace_rcpt", NewReplaceAddr)
}
diff --git a/internal/module/registry.go b/internal/module/registry.go
index 31229f9..1ede212 100644
--- a/internal/module/registry.go
+++ b/internal/module/registry.go
@@ -2,6 +2,8 @@ package module
import (
"sync"
+
+ "github.com/foxcpp/maddy/internal/log"
)
var (
@@ -27,6 +29,17 @@ func Register(name string, factory FuncNewModule) {
modules[name] = factory
}
+// RegisterDeprecated adds module factory function to global registry.
+//
+// It prints warning to the log about name being deprecated and suggests using
+// a new name.
+func RegisterDeprecated(name, newName string, factory FuncNewModule) {
+ Register(name, func(modName, instName string, aliases, inlineArgs []string) (Module, error) {
+ log.Printf("module initialized via deprecated name %s, %s should be used instead; deprecated name may be removed in the next version", name, newName)
+ return factory(modName, instName, aliases, inlineArgs)
+ })
+}
+
// Get returns module from global registry.
//
// This function does not return endpoint-type modules, use GetEndpoint for
diff --git a/internal/msgpipeline/config.go b/internal/msgpipeline/config.go
index 738ec9f..fbbe7e2 100644
--- a/internal/msgpipeline/config.go
+++ b/internal/msgpipeline/config.go
@@ -52,7 +52,7 @@ func parseMsgPipelineRootCfg(globals map[string]interface{}, nodes []config.Node
cfg.globalModifiers.Modifiers = append(cfg.globalModifiers.Modifiers, globalModifiers.Modifiers...)
case "source_in":
var tbl module.Table
- if err := modconfig.ModuleFromNode(node.Args, config.Node{}, globals, &tbl); err != nil {
+ if err := modconfig.ModuleFromNode("table", node.Args, config.Node{}, globals, &tbl); err != nil {
return msgpipelineCfg{}, err
}
srcBlock, err := parseMsgPipelineSrcCfg(globals, node.Children)
@@ -163,7 +163,7 @@ func parseMsgPipelineSrcCfg(globals map[string]interface{}, nodes []config.Node)
src.modifiers.Modifiers = append(src.modifiers.Modifiers, modifiers.Modifiers...)
case "destination_in":
var tbl module.Table
- if err := modconfig.ModuleFromNode(node.Args, config.Node{}, globals, &tbl); err != nil {
+ if err := modconfig.ModuleFromNode("table", node.Args, config.Node{}, globals, &tbl); err != nil {
return sourceBlock{}, err
}
rcptBlock, err := parseMsgPipelineRcptCfg(globals, node.Children)
diff --git a/internal/smtpconn/smtpconn.go b/internal/smtpconn/smtpconn.go
index 448328b..f22a4f9 100644
--- a/internal/smtpconn/smtpconn.go
+++ b/internal/smtpconn/smtpconn.go
@@ -1,4 +1,4 @@
-// The package smtpconn contains the code shared between smtp_downstream and
+// The package smtpconn contains the code shared between target.smtp and
// remote modules.
//
// It implements the wrapper over the SMTP connection (go-smtp.Client) object
diff --git a/internal/smtpconn/smtputf8_test.go b/internal/smtpconn/smtputf8_test.go
index b84e6da..7ef69b9 100644
--- a/internal/smtpconn/smtputf8_test.go
+++ b/internal/smtpconn/smtputf8_test.go
@@ -55,7 +55,7 @@ func TestSMTPUTF8(t *testing.T) {
defer testutils.CheckSMTPConnLeak(t, srv)
c := New()
- c.Log = testutils.Logger(t, "smtp_downstream")
+ c.Log = testutils.Logger(t, "target.smtp")
if _, err := c.Connect(context.Background(), config.Endpoint{
Scheme: "tcp",
Host: "127.0.0.1",
diff --git a/internal/storage/imapsql/imapsql.go b/internal/storage/imapsql/imapsql.go
index 2e7ffad..d49d7a6 100644
--- a/internal/storage/imapsql/imapsql.go
+++ b/internal/storage/imapsql/imapsql.go
@@ -472,5 +472,6 @@ func (store *Storage) Close() error {
}
func init() {
- module.Register("imapsql", New)
+ module.RegisterDeprecated("imapsql", "storage.imapsql", New)
+ module.Register("storage.imapsql", New)
}
diff --git a/internal/table/file.go b/internal/table/file.go
index d2b0c8e..29ed0ff 100644
--- a/internal/table/file.go
+++ b/internal/table/file.go
@@ -15,7 +15,7 @@ import (
"github.com/foxcpp/maddy/internal/module"
)
-const FileModName = "file"
+const FileModName = "table.file"
type File struct {
instName string
@@ -206,5 +206,6 @@ func (f *File) Lookup(val string) (string, bool, error) {
}
func init() {
+ module.RegisterDeprecated("file", "table.file", NewFile)
module.Register(FileModName, NewFile)
}
diff --git a/internal/table/identity.go b/internal/table/identity.go
index e8bbd1e..3f79766 100644
--- a/internal/table/identity.go
+++ b/internal/table/identity.go
@@ -34,5 +34,6 @@ func (s *Identity) Lookup(key string) (string, bool, error) {
}
func init() {
- module.Register("identity", NewIdentity)
+ module.RegisterDeprecated("identity", "table.identity", NewIdentity)
+ module.Register("table.identity", NewIdentity)
}
diff --git a/internal/table/regexp.go b/internal/table/regexp.go
index f550a0a..5a600bb 100644
--- a/internal/table/regexp.go
+++ b/internal/table/regexp.go
@@ -89,5 +89,6 @@ func (r *Regexp) Lookup(key string) (string, bool, error) {
}
func init() {
- module.Register("regexp", NewRegexp)
+ module.RegisterDeprecated("regexp", "table.regexp", NewRegexp)
+ module.Register("table.regexp", NewRegexp)
}
diff --git a/internal/table/sql_query.go b/internal/table/sql_query.go
index 1782723..a29bfd6 100644
--- a/internal/table/sql_query.go
+++ b/internal/table/sql_query.go
@@ -175,5 +175,6 @@ func (s *SQL) SetKey(k, v string) error {
}
func init() {
- module.Register("sql_query", NewSQL)
+ module.RegisterDeprecated("sql_query", "table.sql_query", NewSQL)
+ module.Register("table.sql_query", NewSQL)
}
diff --git a/internal/table/sql_table.go b/internal/table/sql_table.go
index f9ba7c4..1e7d035 100644
--- a/internal/table/sql_table.go
+++ b/internal/table/sql_table.go
@@ -117,5 +117,6 @@ func (s *SQLTable) SetKey(k, v string) error {
}
func init() {
- module.Register("sql_table", NewSQLTable)
+ module.RegisterDeprecated("sql_table", "table.sql_table", NewSQLTable)
+ module.Register("table.sql_table", NewSQLTable)
}
diff --git a/internal/table/static.go b/internal/table/static.go
index 828445c..a329883 100644
--- a/internal/table/static.go
+++ b/internal/table/static.go
@@ -46,5 +46,6 @@ func (s *Static) Lookup(key string) (string, bool, error) {
}
func init() {
- module.Register("static", NewStatic)
+ module.RegisterDeprecated("static", "table.static", NewStatic)
+ module.Register("table.static", NewStatic)
}
diff --git a/internal/target/queue/queue.go b/internal/target/queue/queue.go
index d634020..4ca8126 100644
--- a/internal/target/queue/queue.go
+++ b/internal/target/queue/queue.go
@@ -964,5 +964,6 @@ func (q *Queue) emitDSN(meta *QueueMetadata, header textproto.Header, failedRcpt
}
func init() {
- module.Register("queue", NewQueue)
+ module.RegisterDeprecated("queue", "target.queue", NewQueue)
+ module.Register("target.queue", NewQueue)
}
diff --git a/internal/target/remote/remote.go b/internal/target/remote/remote.go
index ceb2434..2adf61f 100644
--- a/internal/target/remote/remote.go
+++ b/internal/target/remote/remote.go
@@ -491,5 +491,6 @@ func (rd *remoteDelivery) Close() error {
}
func init() {
- module.Register("remote", New)
+ module.RegisterDeprecated("remote", "target.remote", New)
+ module.Register("target.remote", New)
}
diff --git a/internal/target/smtp_downstream/sasl.go b/internal/target/smtp/sasl.go
similarity index 98%
rename from internal/target/smtp_downstream/sasl.go
rename to internal/target/smtp/sasl.go
index 6f27839..acb273d 100644
--- a/internal/target/smtp_downstream/sasl.go
+++ b/internal/target/smtp/sasl.go
@@ -33,7 +33,7 @@ func saslAuthDirective(m *config.Map, node config.Node) (interface{}, error) {
Code: 530,
EnhancedCode: exterrors.EnhancedCode{5, 7, 0},
Message: "Authentication is required",
- TargetName: "smtp_downstream",
+ TargetName: "target.smtp",
Reason: "Credentials forwarding is requested but the client is not authenticated",
}
}
diff --git a/internal/target/smtp_downstream/sasl_test.go b/internal/target/smtp/sasl_test.go
similarity index 93%
rename from internal/target/smtp_downstream/sasl_test.go
rename to internal/target/smtp/sasl_test.go
index 1fbb6ff..93ea9f1 100644
--- a/internal/target/smtp_downstream/sasl_test.go
+++ b/internal/target/smtp/sasl_test.go
@@ -35,7 +35,7 @@ func TestSASL_Plain(t *testing.T) {
},
},
saslFactory: testSaslFactory(t, "plain", "test", "testpass"),
- log: testutils.Logger(t, "smtp_downstream"),
+ log: testutils.Logger(t, "target.smtp"),
}
testutils.DoTestDelivery(t, mod, "test@example.invalid", []string{"rcpt@example.invalid"})
@@ -69,7 +69,7 @@ func TestSASL_Plain_AuthFail(t *testing.T) {
},
},
saslFactory: testSaslFactory(t, "plain", "test", "testpass"),
- log: testutils.Logger(t, "smtp_downstream"),
+ log: testutils.Logger(t, "target.smtp"),
}
_, err := testutils.DoTestDeliveryErr(t, mod, "test@example.invalid", []string{"rcpt@example.invalid"})
@@ -93,7 +93,7 @@ func TestSASL_Forward(t *testing.T) {
},
},
saslFactory: testSaslFactory(t, "forward"),
- log: testutils.Logger(t, "smtp_downstream"),
+ log: testutils.Logger(t, "target.smtp"),
}
testutils.DoTestDeliveryMeta(t, mod, "test@example.invalid", []string{"rcpt@example.invalid"}, &module.MsgMetadata{
@@ -126,7 +126,7 @@ func TestSASL_Forward_NoCreds(t *testing.T) {
},
},
saslFactory: testSaslFactory(t, "forward"),
- log: testutils.Logger(t, "smtp_downstream"),
+ log: testutils.Logger(t, "target.smtp"),
}
_, err := testutils.DoTestDeliveryErr(t, mod, "test@example.invalid", []string{"rcpt@example.invalid"})
diff --git a/internal/target/smtp_downstream/smtp_downstream.go b/internal/target/smtp/smtp_downstream.go
similarity index 94%
rename from internal/target/smtp_downstream/smtp_downstream.go
rename to internal/target/smtp/smtp_downstream.go
index 449af63..b291069 100644
--- a/internal/target/smtp_downstream/smtp_downstream.go
+++ b/internal/target/smtp/smtp_downstream.go
@@ -1,4 +1,4 @@
-// Package smtp_downstream provides smtp_downstream module that implements
+// Package smtp_downstream provides target.smtp module that implements
// transparent forwarding or messages to configured list of SMTP servers.
//
// Like remote module, this implementation doesn't handle atomic
@@ -137,7 +137,7 @@ type lmtpDelivery struct {
}
func (u *Downstream) Start(ctx context.Context, msgMeta *module.MsgMetadata, mailFrom string) (module.Delivery, error) {
- defer trace.StartRegion(ctx, "smtp_downstream/Start").End()
+ defer trace.StartRegion(ctx, "target.smtp/Start").End()
d := &delivery{
u: u,
@@ -285,6 +285,8 @@ func (d *delivery) Commit(ctx context.Context) error {
}
func init() {
- module.Register("smtp_downstream", NewDownstream)
- module.Register("lmtp_downstream", NewDownstream)
+ module.Register("target.smtp", NewDownstream)
+ module.RegisterDeprecated("smtp_downstream", "target.smtp", NewDownstream)
+ module.Register("target.lmtp", NewDownstream)
+ module.RegisterDeprecated("lmtp_downstream", "target.lmtp", NewDownstream)
}
diff --git a/internal/target/smtp_downstream/smtp_downstream_test.go b/internal/target/smtp/smtp_downstream_test.go
similarity index 94%
rename from internal/target/smtp_downstream/smtp_downstream_test.go
rename to internal/target/smtp/smtp_downstream_test.go
index 2e8b2bf..d8726cc 100644
--- a/internal/target/smtp_downstream/smtp_downstream_test.go
+++ b/internal/target/smtp/smtp_downstream_test.go
@@ -39,7 +39,7 @@ func TestDownstreamDelivery(t *testing.T) {
Port: testPort,
},
},
- log: testutils.Logger(t, "smtp_downstream"),
+ log: testutils.Logger(t, "target.smtp"),
}
testutils.DoTestDelivery(t, mod, "test@example.invalid", []string{"rcpt@example.invalid"})
@@ -122,7 +122,7 @@ func TestDownstreamDelivery_Fallback(t *testing.T) {
Port: testPort,
},
},
- log: testutils.Logger(t, "smtp_downstream"),
+ log: testutils.Logger(t, "target.smtp"),
}
testutils.DoTestDelivery(t, mod, "test@example.invalid", []string{"rcpt@example.invalid"})
@@ -149,7 +149,7 @@ func TestDownstreamDelivery_MAILErr(t *testing.T) {
Port: testPort,
},
},
- log: testutils.Logger(t, "smtp_downstream"),
+ log: testutils.Logger(t, "target.smtp"),
}
_, err := testutils.DoTestDeliveryErr(t, mod, "test@example.invalid", []string{"rcpt@example.invalid"})
@@ -172,7 +172,7 @@ func TestDownstreamDelivery_AttemptTLS(t *testing.T) {
},
tlsConfig: *clientCfg.Clone(),
attemptStartTLS: true,
- log: testutils.Logger(t, "smtp_downstream"),
+ log: testutils.Logger(t, "target.smtp"),
}
testutils.DoTestDelivery(t, mod, "test@example.invalid", []string{"rcpt@example.invalid"})
@@ -197,7 +197,7 @@ func TestDownstreamDelivery_AttemptTLS_Fallback(t *testing.T) {
},
},
attemptStartTLS: true,
- log: testutils.Logger(t, "smtp_downstream"),
+ log: testutils.Logger(t, "target.smtp"),
}
testutils.DoTestDelivery(t, mod, "test@example.invalid", []string{"rcpt@example.invalid"})
@@ -221,7 +221,7 @@ func TestDownstreamDelivery_RequireTLS(t *testing.T) {
tlsConfig: *clientCfg.Clone(),
attemptStartTLS: true,
requireTLS: true,
- log: testutils.Logger(t, "smtp_downstream"),
+ log: testutils.Logger(t, "target.smtp"),
}
testutils.DoTestDelivery(t, mod, "test@example.invalid", []string{"rcpt@example.invalid"})
@@ -248,7 +248,7 @@ func TestDownstreamDelivery_RequireTLS_Implicit(t *testing.T) {
tlsConfig: *clientCfg.Clone(),
attemptStartTLS: true,
requireTLS: true,
- log: testutils.Logger(t, "smtp_downstream"),
+ log: testutils.Logger(t, "target.smtp"),
}
testutils.DoTestDelivery(t, mod, "test@example.invalid", []string{"rcpt@example.invalid"})
@@ -274,7 +274,7 @@ func TestDownstreamDelivery_RequireTLS_Fail(t *testing.T) {
},
attemptStartTLS: true,
requireTLS: true,
- log: testutils.Logger(t, "smtp_downstream"),
+ log: testutils.Logger(t, "target.smtp"),
}
_, err := testutils.DoTestDeliveryErr(t, mod, "test@example.invalid", []string{"rcpt@example.invalid"})
diff --git a/internal/target/smtp_downstream/smtputf8_test.go b/internal/target/smtp/smtputf8_test.go
similarity index 100%
rename from internal/target/smtp_downstream/smtputf8_test.go
rename to internal/target/smtp/smtputf8_test.go
diff --git a/maddy.go b/maddy.go
index 4c82bdb..a524ef2 100644
--- a/maddy.go
+++ b/maddy.go
@@ -44,7 +44,7 @@ import (
_ "github.com/foxcpp/maddy/internal/table"
_ "github.com/foxcpp/maddy/internal/target/queue"
_ "github.com/foxcpp/maddy/internal/target/remote"
- _ "github.com/foxcpp/maddy/internal/target/smtp_downstream"
+ _ "github.com/foxcpp/maddy/internal/target/smtp"
)
var (