1
0
mirror of https://blitiri.com.ar/repos/chasquid synced 2026-01-03 17:17:29 +00:00

chasquid: Load and resolve aliases

This patch integrates the aliases resolution into the daemon and queue.

The queue now will resolve aliases at Put time.
This commit is contained in:
Alberto Bertogli
2016-09-22 00:22:39 +01:00
parent bab8a8083c
commit c34c073c1c
15 changed files with 251 additions and 32 deletions

View File

@@ -191,6 +191,10 @@ func (v *Resolver) AddAliasesFile(domain, path string) error {
return nil
}
func (v *Resolver) AddAliasForTesting(addr, rcpt string, rType RType) {
v.aliases[addr] = append(v.aliases[addr], Recipient{rcpt, rType})
}
func (v *Resolver) Reload() error {
newAliases := map[string][]Recipient{}

View File

@@ -75,4 +75,6 @@ func logConfig(c *Config) {
glog.Infof(" Monitoring address: %s", c.MonitoringAddress)
glog.Infof(" MDA: %s %v", c.MailDeliveryAgentBin, c.MailDeliveryAgentArgs)
glog.Infof(" Data directory: %s", c.DataDir)
glog.Infof(" Suffix separators: %s", c.SuffixSeparators)
glog.Infof(" Drop characters: %s", c.DropCharacters)
}

View File

@@ -62,6 +62,16 @@ type Config struct {
// Directory where we store our persistent data.
// Default: "/var/lib/chasquid"
DataDir string `protobuf:"bytes,8,opt,name=data_dir,json=dataDir" json:"data_dir,omitempty"`
// Suffix separator, to perform suffix removal of local users.
// For example, if you set this to "-+", email to local user
// "user-blah" and "user+blah" will be delivered to "user".
// Default: none.
SuffixSeparators string `protobuf:"bytes,9,opt,name=suffix_separators,json=suffixSeparators" json:"suffix_separators,omitempty"`
// Characters to drop from the user part on local emails.
// For example, if you set this to "._", email to local user
// "u.se_r" will be delivered to "user".
// Default: none.
DropCharacters string `protobuf:"bytes,10,opt,name=drop_characters,json=dropCharacters" json:"drop_characters,omitempty"`
}
func (m *Config) Reset() { *m = Config{} }
@@ -76,21 +86,24 @@ func init() {
func init() { proto.RegisterFile("config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 251 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x90, 0x41, 0x2f, 0x04, 0x31,
0x14, 0xc7, 0xb3, 0x3b, 0xcc, 0x8e, 0x67, 0x25, 0xb6, 0x21, 0xca, 0x69, 0xb9, 0x70, 0xe1, 0x22,
0xe2, 0x3c, 0xcc, 0xd5, 0x65, 0x7d, 0x80, 0xa6, 0xd5, 0x1a, 0x2f, 0xd9, 0xb6, 0x9b, 0xbe, 0x12,
0x7c, 0x53, 0xdf, 0x46, 0x5b, 0xcc, 0x4a, 0x38, 0xbe, 0xff, 0xef, 0xf7, 0x6f, 0x5f, 0x1e, 0x4c,
0x1f, 0xbc, 0x7b, 0xc4, 0xfe, 0x62, 0x15, 0x7c, 0xf4, 0x27, 0x1f, 0x63, 0xa8, 0x6f, 0x4b, 0xc0,
0x8e, 0xa0, 0x79, 0xf2, 0x14, 0x9d, 0xb4, 0x86, 0x8f, 0xe6, 0xa3, 0xb3, 0xad, 0xc5, 0x30, 0xb3,
0x53, 0xd8, 0xb5, 0xf2, 0x55, 0x68, 0x19, 0xa5, 0x20, 0x7c, 0x37, 0xc2, 0x2a, 0x3e, 0x4e, 0x4e,
0xb5, 0xd8, 0x49, 0x79, 0x97, 0xe2, 0xfb, 0x94, 0xde, 0x29, 0x76, 0x0c, 0x53, 0xb2, 0x71, 0x25,
0xa4, 0xd6, 0xc1, 0x10, 0xf1, 0x6a, 0x5e, 0xa5, 0x87, 0xb6, 0x73, 0xd6, 0x7e, 0x45, 0xec, 0x1c,
0x18, 0x3d, 0x2b, 0x8b, 0x44, 0xe8, 0xdd, 0x20, 0x6e, 0x14, 0x71, 0xb6, 0x26, 0xbf, 0x74, 0xeb,
0x1d, 0x46, 0x1f, 0xd0, 0xf5, 0x83, 0xbe, 0x59, 0x16, 0x9c, 0xad, 0xc9, 0x8f, 0x7e, 0x05, 0x07,
0x56, 0xe2, 0x52, 0x68, 0xb3, 0xc4, 0x17, 0x13, 0xde, 0x84, 0xec, 0x8d, 0x8b, 0x42, 0xa1, 0xe3,
0x75, 0xe9, 0xec, 0x65, 0xdc, 0x7d, 0xd3, 0x36, 0xc3, 0x1b, 0x74, 0xec, 0x1a, 0xf8, 0x7f, 0x35,
0x19, 0x7a, 0xe2, 0x93, 0xb2, 0xda, 0xfe, 0x9f, 0x5e, 0x9b, 0x20, 0x3b, 0x84, 0xa6, 0x5c, 0x45,
0x63, 0xe0, 0x4d, 0xf9, 0x60, 0x92, 0xe7, 0x0e, 0x83, 0xaa, 0xcb, 0x89, 0x2f, 0x3f, 0x03, 0x00,
0x00, 0xff, 0xff, 0xc5, 0x2e, 0x79, 0xef, 0x72, 0x01, 0x00, 0x00,
// 296 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x91, 0x41, 0x4e, 0xeb, 0x30,
0x10, 0x86, 0xd5, 0x97, 0x47, 0x9a, 0x9a, 0x02, 0xad, 0x05, 0xc2, 0xb0, 0x2a, 0x6c, 0x40, 0x42,
0xb0, 0x41, 0x88, 0x75, 0x68, 0xb6, 0x6c, 0xda, 0x03, 0x58, 0x4e, 0xec, 0xa4, 0x23, 0xd5, 0x76,
0x64, 0x1b, 0x54, 0xb8, 0x14, 0x57, 0x64, 0xe2, 0x42, 0x8a, 0x04, 0xcb, 0xf9, 0xfe, 0x6f, 0xec,
0xf1, 0x98, 0x8c, 0x2b, 0x6b, 0x6a, 0x68, 0xee, 0x5a, 0x67, 0x83, 0xbd, 0xfc, 0x48, 0x48, 0x3a,
0x8f, 0x80, 0x9e, 0x93, 0x6c, 0x65, 0x7d, 0x30, 0x42, 0x2b, 0x36, 0x98, 0x0d, 0xae, 0x47, 0x8b,
0xbe, 0xa6, 0x57, 0x64, 0xa2, 0xc5, 0x86, 0x4b, 0x11, 0x04, 0xf7, 0xf0, 0xae, 0xb8, 0x2e, 0xd9,
0x3f, 0x74, 0x92, 0xc5, 0x01, 0xf2, 0x02, 0xf1, 0x12, 0xe9, 0x73, 0x49, 0x2f, 0xc8, 0xd8, 0xeb,
0xd0, 0x72, 0x21, 0xa5, 0x53, 0xde, 0xb3, 0x64, 0x96, 0xe0, 0x41, 0xfb, 0x1d, 0xcb, 0xb7, 0x88,
0xde, 0x12, 0xea, 0x5f, 0x4a, 0x0d, 0xde, 0x83, 0x35, 0xbd, 0xf8, 0x3f, 0x8a, 0xd3, 0x5d, 0xf2,
0x43, 0xd7, 0xd6, 0x40, 0xb0, 0x0e, 0x4c, 0xd3, 0xeb, 0x7b, 0x71, 0xc0, 0xe9, 0x2e, 0xf9, 0xd6,
0x1f, 0xc8, 0xa9, 0x16, 0xb0, 0xe6, 0x52, 0xad, 0xe1, 0x55, 0xb9, 0x37, 0x2e, 0x1a, 0x65, 0x02,
0x2f, 0xc1, 0xb0, 0x34, 0xf6, 0x1c, 0x77, 0x71, 0xf1, 0x95, 0xe6, 0x5d, 0xf8, 0x04, 0x86, 0x3e,
0x12, 0xf6, 0x57, 0x9b, 0x70, 0x8d, 0x67, 0xc3, 0x38, 0xda, 0xc9, 0xaf, 0xbe, 0x1c, 0x43, 0x7a,
0x46, 0xb2, 0xb8, 0x15, 0x09, 0x8e, 0x65, 0xf1, 0x82, 0x61, 0x57, 0x17, 0xe0, 0xe8, 0x0d, 0xc1,
0xe7, 0xd4, 0x35, 0x6c, 0xb8, 0x57, 0xad, 0x70, 0x02, 0x07, 0xf5, 0x6c, 0x14, 0x9d, 0xc9, 0x36,
0x58, 0xf6, 0x1c, 0x37, 0x7c, 0x24, 0x9d, 0x6d, 0x79, 0xb5, 0x42, 0x52, 0x05, 0x85, 0x2a, 0x89,
0xea, 0x61, 0x87, 0xe7, 0x3d, 0x2d, 0xd3, 0xf8, 0x71, 0xf7, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff,
0xd1, 0x68, 0xa2, 0x22, 0xc8, 0x01, 0x00, 0x00,
}

View File

@@ -42,5 +42,17 @@ message Config {
// Directory where we store our persistent data.
// Default: "/var/lib/chasquid"
string data_dir = 8;
// Suffix separator, to perform suffix removal of local users.
// For example, if you set this to "-+", email to local user
// "user-blah" and "user+blah" will be delivered to "user".
// Default: none.
string suffix_separators = 9;
// Characters to drop from the user part on local emails.
// For example, if you set this to "._", email to local user
// "u.se_r" will be delivered to "user".
// Default: none.
string drop_characters = 10;
}

View File

@@ -19,6 +19,7 @@ import (
"bytes"
"blitiri.com.ar/go/chasquid/internal/aliases"
"blitiri.com.ar/go/chasquid/internal/courier"
"blitiri.com.ar/go/chasquid/internal/envelope"
"blitiri.com.ar/go/chasquid/internal/protoio"
@@ -91,10 +92,13 @@ type Queue struct {
// Path where we store the queue.
path string
// Aliases resolver.
aliases *aliases.Resolver
}
// Load the queue and launch the sending loops on startup.
func New(path string, localDomains *set.String) *Queue {
func New(path string, localDomains *set.String, aliases *aliases.Resolver) *Queue {
os.MkdirAll(path, 0700)
return &Queue{
@@ -103,6 +107,7 @@ func New(path string, localDomains *set.String) *Queue {
remoteC: &courier.SMTP{},
localDomains: localDomains,
path: path,
aliases: aliases,
}
}
@@ -151,11 +156,30 @@ func (q *Queue) Put(from string, to []string, data []byte) (string, error) {
}
for _, t := range to {
item.Rcpt = append(item.Rcpt, &Recipient{
Address: t,
Type: Recipient_EMAIL,
Status: Recipient_PENDING,
})
rcpts, err := q.aliases.Resolve(t)
if err != nil {
return "", fmt.Errorf("error resolving aliases for %q: %v", t, err)
}
// Add the recipients (after resolving aliases); this conversion is
// not very pretty but at least it's self contained.
for _, aliasRcpt := range rcpts {
r := &Recipient{
Address: aliasRcpt.Addr,
Status: Recipient_PENDING,
}
switch aliasRcpt.Type {
case aliases.EMAIL:
r.Type = Recipient_EMAIL
case aliases.PIPE:
r.Type = Recipient_PIPE
default:
glog.Errorf("unknown alias type %v when resolving %q",
aliasRcpt.Type, t)
return "", fmt.Errorf("internal error - unknown alias type")
}
item.Rcpt = append(item.Rcpt, r)
}
}
err := item.WriteTo(q.path)

View File

@@ -3,10 +3,12 @@ package queue
import (
"bytes"
"fmt"
"reflect"
"sync"
"testing"
"time"
"blitiri.com.ar/go/chasquid/internal/aliases"
"blitiri.com.ar/go/chasquid/internal/set"
)
@@ -58,7 +60,7 @@ func newTestCourier() *TestCourier {
func TestBasic(t *testing.T) {
localC := newTestCourier()
remoteC := newTestCourier()
q := New("/tmp/queue_test", set.NewString("loco"))
q := New("/tmp/queue_test", set.NewString("loco"), aliases.NewResolver())
q.localC = localC
q.remoteC = remoteC
@@ -99,7 +101,7 @@ func TestBasic(t *testing.T) {
}
func TestFullQueue(t *testing.T) {
q := New("/tmp/queue_test", set.NewString())
q := New("/tmp/queue_test", set.NewString(), aliases.NewResolver())
// Force-insert maxQueueSize items in the queue.
oneID := ""
@@ -136,8 +138,53 @@ func TestFullQueue(t *testing.T) {
q.Remove(id)
}
// Dumb courier, for when we don't care for the results.
type DumbCourier struct{}
func (c DumbCourier) Deliver(from string, to string, data []byte) error {
return nil
}
func TestAliases(t *testing.T) {
q := New("/tmp/queue_test", set.NewString("loco"), aliases.NewResolver())
q.localC = DumbCourier{}
q.remoteC = DumbCourier{}
q.aliases.AddDomain("loco")
q.aliases.AddAliasForTesting("ab@loco", "pq@loco", aliases.EMAIL)
q.aliases.AddAliasForTesting("ab@loco", "rs@loco", aliases.EMAIL)
q.aliases.AddAliasForTesting("ab@loco", "command", aliases.PIPE)
q.aliases.AddAliasForTesting("cd@loco", "ata@hualpa", aliases.EMAIL)
cases := []struct {
to []string
expected []*Recipient
}{
{[]string{"ab@loco"}, []*Recipient{
{"pq@loco", Recipient_EMAIL, Recipient_PENDING},
{"rs@loco", Recipient_EMAIL, Recipient_PENDING},
{"command", Recipient_PIPE, Recipient_PENDING}}},
{[]string{"ab@loco", "cd@loco"}, []*Recipient{
{"pq@loco", Recipient_EMAIL, Recipient_PENDING},
{"rs@loco", Recipient_EMAIL, Recipient_PENDING},
{"command", Recipient_PIPE, Recipient_PENDING},
{"ata@hualpa", Recipient_EMAIL, Recipient_PENDING}}},
}
for _, c := range cases {
id, err := q.Put("from", c.to, []byte("data"))
if err != nil {
t.Errorf("Put: %v", err)
}
item := q.q[id]
if !reflect.DeepEqual(item.Rcpt, c.expected) {
t.Errorf("case %q, expected %v, got %v", c.to, item.Rcpt, c.expected)
}
q.Remove(id)
}
}
func TestPipes(t *testing.T) {
q := New("/tmp/queue_test", set.NewString("loco"))
q := New("/tmp/queue_test", set.NewString("loco"), aliases.NewResolver())
item := &Item{
Message: Message{
ID: <-newID,