maddy

Fork https://github.com/foxcpp/maddy

git clone git://git.lin.moe/go/maddy.git

  1/*
  2Maddy Mail Server - Composable all-in-one email server.
  3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors
  4
  5This program is free software: you can redistribute it and/or modify
  6it under the terms of the GNU General Public License as published by
  7the Free Software Foundation, either version 3 of the License, or
  8(at your option) any later version.
  9
 10This program is distributed in the hope that it will be useful,
 11but WITHOUT ANY WARRANTY; without even the implied warranty of
 12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13GNU General Public License for more details.
 14
 15You should have received a copy of the GNU General Public License
 16along with this program.  If not, see <https://www.gnu.org/licenses/>.
 17*/
 18
 19package module
 20
 21import (
 22	"crypto/rand"
 23	"crypto/tls"
 24	"encoding/hex"
 25	"io"
 26	"net"
 27
 28	"github.com/emersion/go-smtp"
 29	"github.com/foxcpp/maddy/framework/future"
 30)
 31
 32// ConnState structure holds the state information of the protocol used to
 33// accept this message.
 34type ConnState struct {
 35	// IANA name (ESMTP, ESMTPS, etc) of the protocol message was received
 36	// over. If the message was generated locally, this field is empty.
 37	Proto string
 38
 39	// Information about the SMTP connection, including HELO hostname and
 40	// source IP. Valid only if Proto refers the SMTP protocol or its variant
 41	// (e.g. LMTP).
 42	Hostname   string
 43	LocalAddr  net.Addr
 44	RemoteAddr net.Addr
 45	TLS        tls.ConnectionState
 46
 47	// The RDNSName field contains the result of Reverse DNS lookup on the
 48	// client IP.
 49	//
 50	// The underlying type is the string or untyped nil value. It is the
 51	// message source responsibility to populate this field.
 52	//
 53	// Valid values of this field consumers need to be aware of:
 54	// RDNSName = nil
 55	//   The reverse DNS lookup is not applicable for that message source.
 56	//   Typically the case for messages generated locally.
 57	// RDNSName != nil, but Get returns nil
 58	//   The reverse DNS lookup was attempted, but resulted in an error.
 59	//   Consumers should assume that the PTR record doesn't exist.
 60	RDNSName *future.Future
 61
 62	// If the client successfully authenticated using a username/password pair.
 63	// This field contains the username.
 64	AuthUser string
 65
 66	// If the client successfully authenticated using a username/password pair.
 67	// This field should be cleaned if the ConnState object is serialized
 68	AuthPassword string
 69
 70	ModData ModSpecificData
 71}
 72
 73// MsgMetadata structure contains all information about the origin of
 74// the message and all associated flags indicating how it should be handled
 75// by components.
 76//
 77// All fields should be considered read-only except when otherwise is noted.
 78// Module instances should avoid keeping reference to the instance passed to it
 79// and copy the structure using DeepCopy method instead.
 80//
 81// Compatibility with older values should be considered when changing this
 82// structure since it is serialized to the disk by the queue module using
 83// JSON. Modules should correctly handle missing or invalid values.
 84type MsgMetadata struct {
 85	// Unique identifier for this message. Randomly generated by the
 86	// message source module.
 87	ID string
 88
 89	// Original message sender address as it was received by the message source.
 90	//
 91	// Note that this field is meant for use for tracing purposes.
 92	// All routing and other decisions should be made based on the sender address
 93	// passed separately (for example, mailFrom argument for CheckSender function)
 94	// Note that addresses may contain unescaped Unicode characters.
 95	OriginalFrom string
 96
 97	// If set - no SrcHostname and SrcAddr will be added to Received
 98	// header. These fields are still written to the server log.
 99	DontTraceSender bool
100
101	// Quarantine is a message flag that is should be set if message is
102	// considered "suspicious" and should be put into "Junk" folder
103	// in the storage.
104	//
105	// This field should not be modified by the checks that verify
106	// the message. It is set only by the message pipeline.
107	Quarantine bool
108
109	// OriginalRcpts contains the mapping from the final recipient to the
110	// recipient that was presented by the client.
111	//
112	// MsgPipeline will update that field when recipient modifiers
113	// are executed.
114	//
115	// It should be used when reporting information back to client (via DSN,
116	// for example) to prevent disclosing information about aliases
117	// which is usually unwanted.
118	OriginalRcpts map[string]string
119
120	// SMTPOpts contains the SMTP MAIL FROM command arguments, if the message
121	// was accepted over SMTP or SMTP-like protocol (such as LMTP).
122	//
123	// Note that the Size field should not be used as source of information about
124	// the body size. Especially since it counts the header too whereas
125	// Buffer.Len does not.
126	SMTPOpts smtp.MailOptions
127
128	// Conn contains the information about the underlying protocol connection
129	// that was used to accept this message. The referenced instance may be shared
130	// between multiple messages.
131	//
132	// It can be nil for locally generated messages.
133	Conn *ConnState
134
135	// This is set by endpoint/smtp to indicate that body contains "TLS-Required: No"
136	// header. It is only meaningful if server has seen the body at least once
137	// (e.g. the message was passed via queue).
138	TLSRequireOverride bool
139}
140
141// DeepCopy creates a copy of the MsgMetadata structure, also
142// copying contents of the maps and slices.
143//
144// There are a few exceptions, however:
145// - SrcAddr is not copied and copy field references original value.
146func (msgMeta *MsgMetadata) DeepCopy() *MsgMetadata {
147	cpy := *msgMeta
148	// There is no good way to copy net.Addr, but it should not be
149	// modified by anything anyway so we are safe.
150	return &cpy
151}
152
153// GenerateMsgID generates a string usable as MsgID field in module.MsgMeta.
154func GenerateMsgID() (string, error) {
155	rawID := make([]byte, 4)
156	_, err := io.ReadFull(rand.Reader, rawID)
157	return hex.EncodeToString(rawID), err
158}