mox

package
v0.0.14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 20, 2025 License: MIT Imports: 57 Imported by: 13

Documentation

Overview

Package mox provides functions dealing with global state, such as the current configuration, and convenience functions.

Index

Constants

This section is empty.

Variables

View Source
var (
	ConfigStaticPath  string
	ConfigDynamicPath string
	Conf              = Config{Log: map[string]slog.Level{"": slog.LevelError}}
)

Config paths are set early in program startup. They will point to files in the same directory.

View Source
var (
	ErrDomainNotFound  = errors.New("domain not found")
	ErrAddressNotFound = errors.New("address not found")
)
View Source
var Connections = &connections{
	conns:  map[net.Conn]connKind{},
	gauges: map[connKind]prometheus.GaugeFunc{},
	active: map[connKind]int64{},
}

Connections holds all active protocol sockets (smtp, imap). They will be given an immediate read/write deadline shortly after initiating mox shutdown, after which the connections get 1 more second for error handling before actual shutdown.

This context should be used as parent by most operations. It is canceled 1 second after graceful shutdown was initiated with the cancelation of the Shutdown context. This should abort active operations.

Operations typically have context timeouts, 30s for single i/o like DNS queries, and 1 minute for operations with more back and forth. These are set through a context.WithTimeout based on this context, so those contexts are still canceled when shutting down.

HTTP servers don't get graceful shutdown, their connections are just aborted. todo: should shut down http connections as well, and shut down the listener and/or return 503 for new requests.

View Source
var ContextCancel func()
View Source
var ErrConfig = errors.New("config error")
View Source
var FilesImmediate bool

For privileged file descriptor operations (listen and opening privileged files), perform them immediately, regardless of running as root or other user, in case ForkExecUnprivileged is not used.

View Source
var LicensesFsys fs.FS
View Source
var LimiterFailedAuth *ratelimit.Limiter
View Source
var NewWebaccountHandler = func(basePath string, isForwarded bool) http.Handler { return nopHandler }
View Source
var NewWebadminHandler = func(basePath string, isForwarded bool) http.Handler { return nopHandler }

Set by packages webadmin, webaccount, webmail, webapisrv to prevent cyclic dependencies.

View Source
var NewWebapiHandler = func(maxMsgSize int64, basePath string, isForwarded bool) http.Handler { return nopHandler }
View Source
var NewWebmailHandler = func(maxMsgSize int64, basePath string, isForwarded bool, accountPath string) http.Handler {
	return nopHandler
}
View Source
var Pedantic bool

Pedantic enables stricter parsing.

View Source
var Shutdown context.Context

Shutdown is canceled when a graceful shutdown is initiated. SMTP, IMAP, periodic processes should check this before starting a new operation. If this context is canceled, the operation should not be started, and new connections/commands should receive a message that the service is currently not available.

View Source
var ShutdownCancel func()

Functions

func AcceptsGzip added in v0.0.9

func AcceptsGzip(r *http.Request) bool

AcceptsGzip returns whether the client accepts gzipped responses.

func AllowMsgFrom added in v0.0.11

func AllowMsgFrom(accountName string, msgFrom smtp.Address) bool

AllowMsgFrom returns whether account is allowed to submit messages with address as message From header, based on configured addresses and membership of aliases that allow using its address.

func AsTLSAlert added in v0.0.14

func AsTLSAlert(err error) (alert uint8, ok bool)

func CanonicalLocalpart

func CanonicalLocalpart(localpart smtp.Localpart, d config.Domain) smtp.Localpart

CanonicalLocalpart returns the canonical localpart, removing optional catchall separator, and optionally lower-casing the string.

func Cid

func Cid() int64

Cid returns a new unique id to be used for connections/sessions/requests.

func CidFromCtx added in v0.0.2

func CidFromCtx(ctx context.Context) int64

CidFromCtx returns the cid in the context, or 0.

func CleanupPassedFiles added in v0.0.4

func CleanupPassedFiles()

CleanupPassedFiles closes the listening socket file descriptors and files passed in by the parent process. To be called by the unprivileged child after listeners have been recreated (they dup the file descriptor), and by the privileged process after starting its child.

func ConfigDirPath

func ConfigDirPath(f string) string

ConfigDirPath returns the path to "f". Either f itself when absolute, or interpreted relative to the directory of the static configuration file (mox.conf).

func ConfigDynamicDirPath added in v0.0.14

func ConfigDynamicDirPath(f string) string

Like ConfigDirPath, but relative paths are interpreted relative to the directory of the dynamic configuration file (domains.conf).

func CryptoRandInt

func CryptoRandInt() int64

CryptoRandInt returns a cryptographically random number.

func DKIMSelectors added in v0.0.9

func DKIMSelectors(dkimConf config.DKIM) []dkim.Selector

DKIMSelectors returns the selectors to use for signing.

func DKIMSign added in v0.0.9

func DKIMSign(ctx context.Context, log mlog.Log, from smtp.Path, smtputf8 bool, data []byte) (string, error)

DKIMSign looks up the domain for "from", and uses its DKIM configuration to generate DKIM-Signature headers, for inclusion in a message. The DKIM-Signatur headers, are returned. If no domain was found an empty string and nil error is returned.

func DataDirPath

func DataDirPath(f string) string

DataDirPath returns to the path to "f". Either f itself when absolute, or interpreted relative to the data directory from the currently active configuration.

func DomainSPFIPs added in v0.0.12

func DomainSPFIPs() (ips []net.IP)

DomainSPFIPs returns IPs to include in SPF records for domains. It includes the IPs on listeners that have SMTP enabled, and includes IPs configured for SOCKS transports.

func FallbackMtime added in v0.0.9

func FallbackMtime(log mlog.Log) time.Time

FallbackMtime returns a time to use for the Last-Modified header in case we cannot find a file, e.g. when used in production.

func FillExample added in v0.0.11

func FillExample(seen []reflect.Type, rv reflect.Value) reflect.Value

FillExample returns a modified value with nil/empty maps/slices/pointers values replaced with non-empty versions, for more helpful examples of types. Useful for documenting JSON representations of types.

func FillNil added in v0.0.11

func FillNil(rv reflect.Value) (nv reflect.Value, changed bool)

FillNil returns a modified value with nil maps/slices replaced with empty maps/slices.

func ForkExecUnprivileged added in v0.0.2

func ForkExecUnprivileged()

Fork and exec as unprivileged user.

We don't use just setuid because it is hard to guarantee that no other privileged go worker processes have been started before we get here. E.g. init functions in packages can start goroutines.

func IPs

func IPs(ctx context.Context, receiveOnly bool) ([]net.IP, error)

IPs returns ip addresses we may be listening/receiving mail on or connecting/sending from to the outside.

func LicensesWrite added in v0.0.12

func LicensesWrite(dst io.Writer) error

LicensesWrite writes the licenses to dst.

func LimitersInit

func LimitersInit()

LimitesrsInit initializes the failed auth rate limiter.

func Listen added in v0.0.2

func Listen(network, addr string) (net.Listener, error)

Listen returns a newly created network listener when starting as root, and otherwise (not root) returns a network listener from a file descriptor that was passed by the parent root process.

func LoadConfig

func LoadConfig(ctx context.Context, log mlog.Log, doLoadTLSKeyCerts, checkACMEHosts bool) []error

LoadConfig attempts to parse and load a config, returning any errors encountered.

func LocalserveNeedsError added in v0.0.11

func LocalserveNeedsError(lp smtp.Localpart) (code int, timeout bool)

func LookupAddress added in v0.0.11

func LookupAddress(localpart smtp.Localpart, domain dns.Domain, allowPostmaster, allowAlias bool) (accountName string, alias *config.Alias, canonicalAddress string, dest config.Destination, rerr error)

LookupAddress looks up the account for localpart and domain.

Can return ErrDomainNotFound and ErrAddressNotFound.

func MessageIDGen

func MessageIDGen(smtputf8 bool) string

MessageIDGen returns a generated unique random Message-Id value, excluding <>.

func MustLoadConfig

func MustLoadConfig(doLoadTLSKeyCerts, checkACMEHosts bool)

MustLoadConfig loads the config, quitting on errors.

func Network

func Network(ip string) string

Network returns tcp4 or tcp6, depending on the ip. This network can be passed to Listen instead of "tcp", which may start listening on both ipv4 and ipv6 for addresses 0.0.0.0 and ::, which can lead to errors about the port already being in use. For invalid IPs, "tcp" is returned.

func NewPseudoRand added in v0.0.8

func NewPseudoRand() *rand

NewPseudoRand returns a new PRNG seeded with random bytes from crypto/rand. Its functions can be called concurrently.

func OpenPrivileged added in v0.0.4

func OpenPrivileged(path string) (*os.File, error)

Open a privileged file, such as a TLS private key. When running as root (during startup), the file is opened and the file descriptor is stored. These file descriptors are passed to the unprivileged process. When in the unprivileged processed, we lookup a passed file descriptor. The same calls should be made in the privileged and unprivileged process.

func ParseDynamicConfig

func ParseDynamicConfig(ctx context.Context, log mlog.Log, dynamicPath string, static config.Static) (c config.Dynamic, mtime time.Time, accDests map[string]AccountDestination, aliases map[string]config.Alias, errs []error)

PrepareDynamicConfig parses the dynamic config file given a static file.

func PrepareStaticConfig

func PrepareStaticConfig(ctx context.Context, log mlog.Log, configFile string, conf *Config, checkOnly, doLoadTLSKeyCerts bool) (errs []error)

PrepareStaticConfig parses the static config file and prepares data structures for starting mox. If checkOnly is set no substantial changes are made, like creating an ACME registration.

func ReceivedID

func ReceivedID(cid int64) string

ReceivedID returns an ID for use in a message Received header.

The ID is based on the cid. The cid itself is a counter and would leak the number of connections in received headers. Instead they are obfuscated by encrypting them with AES with a per-install key and random buffer. This allows recovery of the cid based on the id. See subcommand cid.

func ReceivedIDInit

func ReceivedIDInit(key, rand []byte) error

ReceivedIDInit sets an AES key (must be 16 bytes) and random buffer (must be 8 bytes) for use by ReceivedID.

func ReceivedToCid

func ReceivedToCid(s string) (cid int64, err error)

ReceivedToCid returns the cid given a ReceivedID.

func RestorePassedFiles added in v0.0.4

func RestorePassedFiles()

RestorePassedFiles reads addresses from $MOX_SOCKETS and paths from $MOX_FILES and prepares an os.File for each file descriptor, which are used by later calls of Listen or opening files.

func SafeHeaders added in v0.0.12

func SafeHeaders(fn http.Handler) http.Handler

Set some http headers that should prevent potential abuse. Better safe than sorry.

func SetConfig

func SetConfig(c *Config)

SetConfig sets a new config. Not to be used during normal operation.

func SetPedantic added in v0.0.9

func SetPedantic(p bool)

Set pedantic in all packages.

func Sleep

func Sleep(ctx context.Context, d time.Duration) (ctxDone bool)

Sleep for d, but return as soon as ctx is done.

Used for a few places where sleep is used to push back on clients, but where shutting down should abort the sleep.

func StartTLSSessionTicketKeyRefresher added in v0.0.14

func StartTLSSessionTicketKeyRefresher(ctx context.Context, log mlog.Log, c *tls.Config)

StartTLSSessionTicketKeyRefresher sets session keys on the TLS config, and rotates them periodically.

Useful for TLS configs that are being cloned for each connection. The automatically managed keys would happen in the cloned config, and not make it back to the base config.

func TLSReceivedComment added in v0.0.9

func TLSReceivedComment(log mlog.Log, cs tls.ConnectionState) []string

TLSReceivedComment returns a comment about TLS of the connection for use in a Receive header.

func TXTStrings

func TXTStrings(s string) string

TXTStrings returns a TXT record value as one or more quoted strings, each max 100 characters. In case of multiple strings, a multi-line record is returned.

func WriteDynamicLocked added in v0.0.14

func WriteDynamicLocked(ctx context.Context, log mlog.Log, c config.Dynamic) error

WriteDynamicLocked prepares an updated internal state for the new dynamic config, then writes it to disk and activates it.

Returns ErrConfig if the configuration is not valid.

Must be called with config lock held.

Types

type AccountDestination

type AccountDestination struct {
	Catchall    bool           // If catchall destination for its domain.
	Localpart   smtp.Localpart // In original casing as written in config file.
	Account     string
	Destination config.Destination
}

type Config

type Config struct {
	Static config.Static // Does not change during the lifetime of a running instance.

	Log map[string]slog.Level

	Dynamic config.Dynamic // Can only be accessed directly by tests. Use methods on Config for locked access.

	DynamicLastCheck time.Time // For use by quickstart only to skip checks.

	// From canonical full address (localpart@domain, lower-cased when
	// case-insensitive, stripped of catchall separator) to account and address.
	// Domains are IDNA names in utf8. Dynamic config lock must be held when accessing.
	AccountDestinationsLocked map[string]AccountDestination
	// contains filtered or unexported fields
}

Config as used in the code, a processed version of what is in the config file.

Use methods to lookup a domain/account/address in the dynamic configuration.

func ParseConfig

func ParseConfig(ctx context.Context, log mlog.Log, p string, checkOnly, doLoadTLSKeyCerts, checkACMEHosts bool) (c *Config, errs []error)

ParseConfig parses the static config at path p. If checkOnly is true, no changes are made, such as registering ACME identities. If doLoadTLSKeyCerts is true, the TLS KeyCerts configuration is loaded and checked. This is used during the quickstart in the case the user is going to provide their own certificates. If checkACMEHosts is true, the hosts allowed for acme are compared with the explicitly configured ips we are listening on.

func (*Config) Account

func (c *Config) Account(name string) (acc config.Account, ok bool)

func (*Config) AccountDestination

func (c *Config) AccountDestination(addr string) (accDest AccountDestination, alias *config.Alias, ok bool)

func (*Config) Accounts

func (c *Config) Accounts() (l []string)

func (*Config) Domain

func (c *Config) Domain(d dns.Domain) (dom config.Domain, ok bool)

func (*Config) DomainLocalparts

func (c *Config) DomainLocalparts(d dns.Domain) (map[string]string, map[string]config.Alias)

DomainLocalparts returns a mapping of encoded localparts to account names for a domain, and encoded localparts to aliases. An empty localpart is a catchall destination for a domain.

func (*Config) Domains

func (c *Config) Domains() (l []string)

func (*Config) DynamicConfig added in v0.0.11

func (c *Config) DynamicConfig() (config config.Dynamic)

DynamicConfig returns a shallow copy of the dynamic config. Must not be modified.

func (*Config) DynamicLockUnlock added in v0.0.14

func (c *Config) DynamicLockUnlock() func()

DynamicLockUnlock locks the dynamic config, will try updating the latest state from disk, and return an unlock function. Should be called as "defer Conf.DynamicLockUnlock()()".

func (*Config) IsClientSettingsDomain added in v0.0.12

func (c *Config) IsClientSettingsDomain(d dns.Domain) (is bool)

func (*Config) LogLevelRemove

func (c *Config) LogLevelRemove(log mlog.Log, pkg string)

LogLevelRemove removes a configured log level for a package.

func (*Config) LogLevelSet

func (c *Config) LogLevelSet(log mlog.Log, pkg string, level slog.Level)

LogLevelSet sets a new log level for pkg. An empty pkg sets the default log value that is used if no explicit log level is configured for a package. This change is ephemeral, no config file is changed.

func (*Config) LogLevels

func (c *Config) LogLevels() map[string]slog.Level

LogLevels returns a copy of the current log levels.

func (*Config) Routes added in v0.0.5

func (c *Config) Routes(accountName string, domain dns.Domain) (accountRoutes, domainRoutes, globalRoutes []config.Route)

type WebappFile added in v0.0.9

type WebappFile struct {
	HTML, JS         []byte // Embedded html/js data.
	HTMLPath, JSPath string // Paths to load html/js from during development.
	CustomStem       string // For trying to read css/js customizations from $configdir/$stem.{css,js}.

	sync.Mutex
	// contains filtered or unexported fields
}

WebappFile serves a merged HTML and JS webapp as a single compressed, cacheable file. It merges the JS into the HTML at first load, caches a gzipped version that is generated on first need, and responds with a Last-Modified header.

func (*WebappFile) Serve added in v0.0.9

func (a *WebappFile) Serve(ctx context.Context, log mlog.Log, w http.ResponseWriter, r *http.Request)

Serve serves a combined file, with headers for caching and possibly gzipped.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL