This repository has been archived by the owner on Apr 29, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathbackend.go
137 lines (116 loc) · 2.35 KB
/
backend.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package proxy
import (
"crypto/tls"
"errors"
"net"
"github.com/emersion/go-sasl"
"github.com/emersion/go-smtp"
)
type Security int
const (
SecurityTLS Security = iota
SecurityStartTLS
SecurityNone
)
type Backend struct {
Addr string
Security Security
TLSConfig *tls.Config
LMTP bool
Host string
LocalName string
unexported struct{}
}
func New(addr string) *Backend {
return &Backend{Addr: addr, Security: SecurityStartTLS}
}
func NewTLS(addr string, tlsConfig *tls.Config) *Backend {
return &Backend{
Addr: addr,
Security: SecurityTLS,
TLSConfig: tlsConfig,
}
}
func NewLMTP(addr string, host string) *Backend {
return &Backend{
Addr: addr,
Security: SecurityNone,
LMTP: true,
Host: host,
}
}
func (be *Backend) newConn() (*smtp.Client, error) {
var conn net.Conn
var err error
if be.LMTP {
if be.Security != SecurityNone {
return nil, errors.New("smtp-proxy: LMTP doesn't support TLS")
}
conn, err = net.Dial("unix", be.Addr)
} else if be.Security == SecurityTLS {
conn, err = tls.Dial("tcp", be.Addr, be.TLSConfig)
} else {
conn, err = net.Dial("tcp", be.Addr)
}
if err != nil {
return nil, err
}
var c *smtp.Client
if be.LMTP {
c, err = smtp.NewClientLMTP(conn, be.Host)
} else {
host := be.Host
if host == "" {
host, _, _ = net.SplitHostPort(be.Addr)
}
c, err = smtp.NewClient(conn, host)
}
if err != nil {
return nil, err
}
if be.LocalName != "" {
err = c.Hello(be.LocalName)
if err != nil {
return nil, err
}
}
if be.Security == SecurityStartTLS {
if err := c.StartTLS(be.TLSConfig); err != nil {
return nil, err
}
}
return c, nil
}
func (be *Backend) login(username, password string) (*smtp.Client, error) {
c, err := be.newConn()
if err != nil {
return nil, err
}
auth := sasl.NewPlainClient("", username, password)
if err := c.Auth(auth); err != nil {
return nil, err
}
return c, nil
}
func (be *Backend) Login(state *smtp.ConnectionState, username, password string) (smtp.Session, error) {
c, err := be.login(username, password)
if err != nil {
return nil, err
}
s := &session{
c: c,
be: be,
}
return s, nil
}
func (be *Backend) AnonymousLogin(state *smtp.ConnectionState) (smtp.Session, error) {
c, err := be.newConn()
if err != nil {
return nil, err
}
s := &session{
c: c,
be: be,
}
return s, nil
}