server.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. package guerrilla
  2. import (
  3. "bytes"
  4. "crypto/rand"
  5. "crypto/tls"
  6. "crypto/x509"
  7. "fmt"
  8. "github.com/sirupsen/logrus"
  9. "io"
  10. "io/ioutil"
  11. "net"
  12. "path/filepath"
  13. "strings"
  14. "sync"
  15. "sync/atomic"
  16. "time"
  17. "github.com/flashmob/go-guerrilla/backends"
  18. "github.com/flashmob/go-guerrilla/log"
  19. "github.com/flashmob/go-guerrilla/mail"
  20. "github.com/flashmob/go-guerrilla/mail/rfc5321"
  21. "github.com/flashmob/go-guerrilla/response"
  22. )
  23. const (
  24. CommandVerbMaxLength = 16
  25. CommandLineMaxLength = 1024
  26. // Number of allowed unrecognized commands before we terminate the connection
  27. MaxUnrecognizedCommands = 5
  28. )
  29. const (
  30. // server has just been created
  31. ServerStateNew = iota
  32. // Server has just been stopped
  33. ServerStateStopped
  34. // Server has been started and is running
  35. ServerStateRunning
  36. // Server could not start due to an error
  37. ServerStateStartError
  38. )
  39. // Server listens for SMTP clients on the port specified in its config
  40. type server struct {
  41. configStore atomic.Value // stores guerrilla.ServerConfig
  42. tlsConfigStore atomic.Value
  43. timeout atomic.Value // stores time.Duration
  44. listenInterface string
  45. clientPool *Pool
  46. wg sync.WaitGroup // for waiting to shutdown
  47. listener net.Listener
  48. closedListener chan bool
  49. hosts allowedHosts // stores map[string]bool for faster lookup
  50. state int
  51. // If log changed after a config reload, newLogStore stores the value here until it's safe to change it
  52. logStore atomic.Value
  53. mainlogStore atomic.Value
  54. backendStore atomic.Value
  55. envelopePool *mail.Pool
  56. }
  57. type allowedHosts struct {
  58. table map[string]bool // host lookup table
  59. wildcards []string // host wildcard list (* is used as a wildcard)
  60. sync.Mutex // guard access to the map
  61. }
  62. type command []byte
  63. var (
  64. cmdHELO command = []byte("HELO")
  65. cmdEHLO command = []byte("EHLO")
  66. cmdHELP command = []byte("HELP")
  67. cmdXCLIENT command = []byte("XCLIENT")
  68. cmdMAIL command = []byte("MAIL FROM:")
  69. cmdRCPT command = []byte("RCPT TO:")
  70. cmdRSET command = []byte("RSET")
  71. cmdVRFY command = []byte("VRFY")
  72. cmdNOOP command = []byte("NOOP")
  73. cmdQUIT command = []byte("QUIT")
  74. cmdDATA command = []byte("DATA")
  75. cmdSTARTTLS command = []byte("STARTTLS")
  76. )
  77. func (c command) match(in []byte) bool {
  78. return bytes.Index(in, []byte(c)) == 0
  79. }
  80. // Creates and returns a new ready-to-run Server from a ServerConfig configuration
  81. func newServer(sc *ServerConfig, b backends.Backend, mainlog log.Logger) (*server, error) {
  82. server := &server{
  83. clientPool: NewPool(sc.MaxClients),
  84. closedListener: make(chan bool, 1),
  85. listenInterface: sc.ListenInterface,
  86. state: ServerStateNew,
  87. envelopePool: mail.NewPool(sc.MaxClients),
  88. }
  89. server.mainlogStore.Store(mainlog)
  90. server.backendStore.Store(b)
  91. if sc.LogFile == "" {
  92. // none set, use the mainlog for the server log
  93. server.logStore.Store(mainlog)
  94. server.log().Info("server [" + sc.ListenInterface + "] did not configure a separate log file, so using the main log")
  95. } else {
  96. // set level to same level as mainlog level
  97. if l, logOpenError := log.GetLogger(sc.LogFile, server.mainlog().GetLevel()); logOpenError != nil {
  98. server.log().WithError(logOpenError).Errorf("Failed creating a logger for server [%s]", sc.ListenInterface)
  99. return server, logOpenError
  100. } else {
  101. server.logStore.Store(l)
  102. }
  103. }
  104. server.setConfig(sc)
  105. server.setTimeout(sc.Timeout)
  106. if err := server.configureTLS(); err != nil {
  107. return server, err
  108. }
  109. return server, nil
  110. }
  111. func (s *server) configureTLS() error {
  112. sConfig := s.configStore.Load().(ServerConfig)
  113. if sConfig.TLS.AlwaysOn || sConfig.TLS.StartTLSOn {
  114. cert, err := tls.LoadX509KeyPair(sConfig.TLS.PublicKeyFile, sConfig.TLS.PrivateKeyFile)
  115. if err != nil {
  116. return fmt.Errorf("error while loading the certificate: %s", err)
  117. }
  118. tlsConfig := &tls.Config{
  119. Certificates: []tls.Certificate{cert},
  120. ClientAuth: tls.VerifyClientCertIfGiven,
  121. ServerName: sConfig.Hostname,
  122. }
  123. if len(sConfig.TLS.Protocols) > 0 {
  124. if min, ok := TLSProtocols[sConfig.TLS.Protocols[0]]; ok {
  125. tlsConfig.MinVersion = min
  126. }
  127. }
  128. if len(sConfig.TLS.Protocols) > 1 {
  129. if max, ok := TLSProtocols[sConfig.TLS.Protocols[1]]; ok {
  130. tlsConfig.MaxVersion = max
  131. }
  132. }
  133. if len(sConfig.TLS.Ciphers) > 0 {
  134. for _, val := range sConfig.TLS.Ciphers {
  135. if c, ok := TLSCiphers[val]; ok {
  136. tlsConfig.CipherSuites = append(tlsConfig.CipherSuites, c)
  137. }
  138. }
  139. }
  140. if len(sConfig.TLS.Curves) > 0 {
  141. for _, val := range sConfig.TLS.Curves {
  142. if c, ok := TLSCurves[val]; ok {
  143. tlsConfig.CurvePreferences = append(tlsConfig.CurvePreferences, c)
  144. }
  145. }
  146. }
  147. if len(sConfig.TLS.RootCAs) > 0 {
  148. caCert, err := ioutil.ReadFile(sConfig.TLS.RootCAs)
  149. if err != nil {
  150. s.log().WithError(err).Errorf("failed opening TLSRootCAs file [%s]", sConfig.TLS.RootCAs)
  151. } else {
  152. caCertPool := x509.NewCertPool()
  153. caCertPool.AppendCertsFromPEM(caCert)
  154. tlsConfig.RootCAs = caCertPool
  155. }
  156. }
  157. if len(sConfig.TLS.ClientAuthType) > 0 {
  158. if ca, ok := TLSClientAuthTypes[sConfig.TLS.ClientAuthType]; ok {
  159. tlsConfig.ClientAuth = ca
  160. }
  161. }
  162. tlsConfig.PreferServerCipherSuites = sConfig.TLS.PreferServerCipherSuites
  163. tlsConfig.Rand = rand.Reader
  164. s.tlsConfigStore.Store(tlsConfig)
  165. }
  166. return nil
  167. }
  168. // setBackend sets the backend to use for processing email envelopes
  169. func (s *server) setBackend(b backends.Backend) {
  170. s.backendStore.Store(b)
  171. }
  172. // backend gets the backend used to process email envelopes
  173. func (s *server) backend() backends.Backend {
  174. if b, ok := s.backendStore.Load().(backends.Backend); ok {
  175. return b
  176. }
  177. return nil
  178. }
  179. // Set the timeout for the server and all clients
  180. func (s *server) setTimeout(seconds int) {
  181. duration := time.Duration(int64(seconds))
  182. s.clientPool.SetTimeout(duration)
  183. s.timeout.Store(duration)
  184. }
  185. // goroutine safe config store
  186. func (s *server) setConfig(sc *ServerConfig) {
  187. s.configStore.Store(*sc)
  188. }
  189. // goroutine safe
  190. func (s *server) isEnabled() bool {
  191. sc := s.configStore.Load().(ServerConfig)
  192. return sc.IsEnabled
  193. }
  194. // Set the allowed hosts for the server
  195. func (s *server) setAllowedHosts(allowedHosts []string) {
  196. s.hosts.Lock()
  197. defer s.hosts.Unlock()
  198. s.hosts.table = make(map[string]bool, len(allowedHosts))
  199. s.hosts.wildcards = nil
  200. for _, h := range allowedHosts {
  201. if strings.Contains(h, "*") {
  202. s.hosts.wildcards = append(s.hosts.wildcards, strings.ToLower(h))
  203. } else if len(h) > 5 && h[0] == '[' && h[len(h)-1] == ']' {
  204. if ip := net.ParseIP(h[1 : len(h)-1]); ip != nil {
  205. // this will save the normalized ip, as ip.String always returns ipv6 in short form
  206. s.hosts.table["["+ip.String()+"]"] = true
  207. }
  208. } else {
  209. s.hosts.table[strings.ToLower(h)] = true
  210. }
  211. }
  212. }
  213. // Begin accepting SMTP clients. Will block unless there is an error or server.Shutdown() is called
  214. func (s *server) Start(startWG *sync.WaitGroup) error {
  215. var clientID uint64
  216. clientID = 0
  217. listener, err := net.Listen("tcp", s.listenInterface)
  218. s.listener = listener
  219. if err != nil {
  220. startWG.Done() // don't wait for me
  221. s.state = ServerStateStartError
  222. return fmt.Errorf("[%s] Cannot listen on port: %s ", s.listenInterface, err.Error())
  223. }
  224. s.log().Infof("Listening on TCP %s", s.listenInterface)
  225. s.state = ServerStateRunning
  226. startWG.Done() // start successful, don't wait for me
  227. for {
  228. s.log().Debugf("[%s] Waiting for a new client. Next Client ID: %d", s.listenInterface, clientID+1)
  229. conn, err := listener.Accept()
  230. clientID++
  231. if err != nil {
  232. if e, ok := err.(net.Error); ok && !e.Temporary() {
  233. s.log().Infof("Server [%s] has stopped accepting new clients", s.listenInterface)
  234. // the listener has been closed, wait for clients to exit
  235. s.log().Infof("shutting down pool [%s]", s.listenInterface)
  236. s.clientPool.ShutdownState()
  237. s.clientPool.ShutdownWait()
  238. s.state = ServerStateStopped
  239. s.closedListener <- true
  240. return nil
  241. }
  242. s.mainlog().WithError(err).Info("Temporary error accepting client")
  243. continue
  244. }
  245. go func(p Poolable, borrowErr error) {
  246. c := p.(*client)
  247. if borrowErr == nil {
  248. s.handleClient(c)
  249. s.envelopePool.Return(c.Envelope)
  250. s.clientPool.Return(c)
  251. } else {
  252. s.log().WithError(borrowErr).Info("couldn't borrow a new client")
  253. // we could not get a client, so close the connection.
  254. _ = conn.Close()
  255. }
  256. // intentionally placed Borrow in args so that it's called in the
  257. // same main goroutine.
  258. }(s.clientPool.Borrow(conn, clientID, s.log(), s.envelopePool))
  259. }
  260. }
  261. func (s *server) Shutdown() {
  262. if s.listener != nil {
  263. // This will cause Start function to return, by causing an error on listener.Accept
  264. _ = s.listener.Close()
  265. // wait for the listener to listener.Accept
  266. <-s.closedListener
  267. // At this point Start will exit and close down the pool
  268. } else {
  269. s.clientPool.ShutdownState()
  270. // listener already closed, wait for clients to exit
  271. s.clientPool.ShutdownWait()
  272. s.state = ServerStateStopped
  273. }
  274. }
  275. func (s *server) GetActiveClientsCount() int {
  276. return s.clientPool.GetActiveClientsCount()
  277. }
  278. // Verifies that the host is a valid recipient.
  279. // host checking turned off if there is a single entry and it's a dot.
  280. func (s *server) allowsHost(host string) bool {
  281. s.hosts.Lock()
  282. defer s.hosts.Unlock()
  283. // if hosts contains a single dot, further processing is skipped
  284. if len(s.hosts.table) == 1 {
  285. if _, ok := s.hosts.table["."]; ok {
  286. return true
  287. }
  288. }
  289. if _, ok := s.hosts.table[strings.ToLower(host)]; ok {
  290. return true
  291. }
  292. // check the wildcards
  293. for _, w := range s.hosts.wildcards {
  294. if matched, err := filepath.Match(w, strings.ToLower(host)); matched && err == nil {
  295. return true
  296. }
  297. }
  298. return false
  299. }
  300. func (s *server) allowsIp(ip net.IP) bool {
  301. ipStr := ip.String()
  302. return s.allowsHost("[" + ipStr + "]")
  303. }
  304. const commandSuffix = "\r\n"
  305. // Reads from the client until a \n terminator is encountered,
  306. // or until a timeout occurs.
  307. func (s *server) readCommand(client *client) ([]byte, error) {
  308. //var input string
  309. var err error
  310. var bs []byte
  311. // In command state, stop reading at line breaks
  312. bs, err = client.bufin.ReadSlice('\n')
  313. if err != nil {
  314. return bs, err
  315. } else if bytes.HasSuffix(bs, []byte(commandSuffix)) {
  316. return bs[:len(bs)-2], err
  317. }
  318. return bs[:len(bs)-1], err
  319. }
  320. // flushResponse a response to the client. Flushes the client.bufout buffer to the connection
  321. func (s *server) flushResponse(client *client) error {
  322. if err := client.setTimeout(s.timeout.Load().(time.Duration)); err != nil {
  323. return err
  324. }
  325. return client.bufout.Flush()
  326. }
  327. func (s *server) isShuttingDown() bool {
  328. return s.clientPool.IsShuttingDown()
  329. }
  330. // Handles an entire client SMTP exchange
  331. func (s *server) handleClient(client *client) {
  332. defer client.closeConn()
  333. sc := s.configStore.Load().(ServerConfig)
  334. s.log().Infof("Handle client [%s], id: %d", client.RemoteIP, client.ID)
  335. // Initial greeting
  336. greeting := fmt.Sprintf("220 %s SMTP Guerrilla(%s) #%d (%d) %s",
  337. sc.Hostname, Version, client.ID,
  338. s.clientPool.GetActiveClientsCount(), time.Now().Format(time.RFC3339))
  339. helo := fmt.Sprintf("250 %s Hello", sc.Hostname)
  340. // ehlo is a multi-line reply and need additional \r\n at the end
  341. ehlo := fmt.Sprintf("250-%s Hello\r\n", sc.Hostname)
  342. // Extended feature advertisements
  343. messageSize := fmt.Sprintf("250-SIZE %d\r\n", sc.MaxSize)
  344. pipelining := "250-PIPELINING\r\n"
  345. advertiseTLS := "250-STARTTLS\r\n"
  346. advertiseEnhancedStatusCodes := "250-ENHANCEDSTATUSCODES\r\n"
  347. // The last line doesn't need \r\n since string will be printed as a new line.
  348. // Also, Last line has no dash -
  349. help := "250 HELP"
  350. if sc.TLS.AlwaysOn {
  351. tlsConfig, ok := s.tlsConfigStore.Load().(*tls.Config)
  352. if !ok {
  353. s.mainlog().Error("Failed to load *tls.Config")
  354. } else if err := client.upgradeToTLS(tlsConfig); err == nil {
  355. advertiseTLS = ""
  356. } else {
  357. s.log().WithError(err).Warnf("[%s] Failed TLS handshake", client.RemoteIP)
  358. // server requires TLS, but can't handshake
  359. client.kill()
  360. }
  361. }
  362. if !sc.TLS.StartTLSOn {
  363. // STARTTLS turned off, don't advertise it
  364. advertiseTLS = ""
  365. }
  366. r := response.Canned
  367. for client.isAlive() {
  368. switch client.state {
  369. case ClientGreeting:
  370. client.sendResponse(greeting)
  371. client.state = ClientCmd
  372. case ClientCmd:
  373. client.bufin.setLimit(CommandLineMaxLength)
  374. input, err := s.readCommand(client)
  375. s.log().Debugf("Client sent: %s", input)
  376. if err == io.EOF {
  377. s.log().WithError(err).Warnf("Client closed the connection: %s", client.RemoteIP)
  378. return
  379. } else if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
  380. s.log().WithError(err).Warnf("Timeout: %s", client.RemoteIP)
  381. return
  382. } else if err == LineLimitExceeded {
  383. client.sendResponse(r.FailLineTooLong)
  384. client.kill()
  385. break
  386. } else if err != nil {
  387. s.log().WithError(err).Warnf("Read error: %s", client.RemoteIP)
  388. client.kill()
  389. break
  390. }
  391. if s.isShuttingDown() {
  392. client.state = ClientShutdown
  393. continue
  394. }
  395. cmdLen := len(input)
  396. if cmdLen > CommandVerbMaxLength {
  397. cmdLen = CommandVerbMaxLength
  398. }
  399. cmd := bytes.ToUpper(input[:cmdLen])
  400. switch {
  401. case cmdHELO.match(cmd):
  402. if h, err := client.parser.Helo(input[4:]); err == nil {
  403. client.Helo = h
  404. } else {
  405. s.log().WithFields(logrus.Fields{"helo": h, "client": client.ID}).Warn("invalid helo")
  406. client.sendResponse(r.FailSyntaxError)
  407. break
  408. }
  409. client.resetTransaction()
  410. client.sendResponse(helo)
  411. case cmdEHLO.match(cmd):
  412. if h, _, err := client.parser.Ehlo(input[4:]); err == nil {
  413. client.Helo = h
  414. } else {
  415. client.sendResponse(r.FailSyntaxError)
  416. s.log().WithFields(logrus.Fields{"ehlo": h, "client": client.ID}).Warn("invalid ehlo")
  417. client.sendResponse(r.FailSyntaxError)
  418. break
  419. }
  420. client.ESMTP = true
  421. client.resetTransaction()
  422. client.sendResponse(ehlo,
  423. messageSize,
  424. pipelining,
  425. advertiseTLS,
  426. advertiseEnhancedStatusCodes,
  427. help)
  428. case cmdHELP.match(cmd):
  429. quote := response.GetQuote()
  430. client.sendResponse("214-OK\r\n", quote)
  431. case sc.XClientOn && cmdXCLIENT.match(cmd):
  432. if toks := bytes.Split(input[8:], []byte{' '}); len(toks) > 0 {
  433. for i := range toks {
  434. if vals := bytes.Split(toks[i], []byte{'='}); len(vals) == 2 {
  435. if bytes.Equal(vals[1], []byte("[UNAVAILABLE]")) {
  436. // skip
  437. continue
  438. }
  439. if bytes.Equal(vals[0], []byte("ADDR")) {
  440. client.RemoteIP = string(vals[1])
  441. }
  442. if bytes.Equal(vals[0], []byte("HELO")) {
  443. client.Helo = string(vals[1])
  444. }
  445. }
  446. }
  447. }
  448. client.sendResponse(r.SuccessMailCmd)
  449. case cmdMAIL.match(cmd):
  450. if client.isInTransaction() {
  451. client.sendResponse(r.FailNestedMailCmd)
  452. break
  453. }
  454. client.MailFrom, err = client.parsePath(input[10:], client.parser.MailFrom)
  455. if err != nil {
  456. s.log().WithError(err).Error("MAIL parse error", "["+string(input[10:])+"]")
  457. client.sendResponse(err)
  458. break
  459. } else if client.parser.NullPath {
  460. // bounce has empty from address
  461. client.MailFrom = mail.Address{}
  462. }
  463. client.sendResponse(r.SuccessMailCmd)
  464. case cmdRCPT.match(cmd):
  465. if len(client.RcptTo) > rfc5321.LimitRecipients {
  466. client.sendResponse(r.ErrorTooManyRecipients)
  467. break
  468. }
  469. to, err := client.parsePath(input[8:], client.parser.RcptTo)
  470. if err != nil {
  471. s.log().WithError(err).Error("RCPT parse error", "["+string(input[8:])+"]")
  472. client.sendResponse(err.Error())
  473. break
  474. }
  475. s.defaultHost(&to)
  476. if (to.IP != nil && !s.allowsIp(to.IP)) || (to.IP == nil && !s.allowsHost(to.Host)) {
  477. client.sendResponse(r.ErrorRelayDenied, " ", to.Host)
  478. } else {
  479. client.PushRcpt(to)
  480. rcptError := s.backend().ValidateRcpt(client.Envelope)
  481. if rcptError != nil {
  482. client.PopRcpt()
  483. client.sendResponse(r.FailRcptCmd, " ", rcptError.Error())
  484. } else {
  485. client.sendResponse(r.SuccessRcptCmd)
  486. }
  487. }
  488. case cmdRSET.match(cmd):
  489. client.resetTransaction()
  490. client.sendResponse(r.SuccessResetCmd)
  491. case cmdVRFY.match(cmd):
  492. client.sendResponse(r.SuccessVerifyCmd)
  493. case cmdNOOP.match(cmd):
  494. client.sendResponse(r.SuccessNoopCmd)
  495. case cmdQUIT.match(cmd):
  496. client.sendResponse(r.SuccessQuitCmd)
  497. client.kill()
  498. case cmdDATA.match(cmd):
  499. if len(client.RcptTo) == 0 {
  500. client.sendResponse(r.FailNoRecipientsDataCmd)
  501. break
  502. }
  503. client.sendResponse(r.SuccessDataCmd)
  504. client.state = ClientData
  505. case sc.TLS.StartTLSOn && cmdSTARTTLS.match(cmd):
  506. client.sendResponse(r.SuccessStartTLSCmd)
  507. client.state = ClientStartTLS
  508. default:
  509. client.errors++
  510. if client.errors >= MaxUnrecognizedCommands {
  511. client.sendResponse(r.FailMaxUnrecognizedCmd)
  512. client.kill()
  513. } else {
  514. client.sendResponse(r.FailUnrecognizedCmd)
  515. }
  516. }
  517. case ClientData:
  518. // intentionally placed the limit 1MB above so that reading does not return with an error
  519. // if the client goes a little over. Anything above will err
  520. client.bufin.setLimit(sc.MaxSize + 1024000) // This a hard limit.
  521. n, err := client.Data.ReadFrom(client.smtpReader.DotReader())
  522. if n > sc.MaxSize {
  523. err = fmt.Errorf("maximum DATA size exceeded (%d)", sc.MaxSize)
  524. }
  525. if err != nil {
  526. if err == LineLimitExceeded {
  527. client.sendResponse(r.FailReadLimitExceededDataCmd, " ", LineLimitExceeded.Error())
  528. client.kill()
  529. } else if err == MessageSizeExceeded {
  530. client.sendResponse(r.FailMessageSizeExceeded, " ", MessageSizeExceeded.Error())
  531. client.kill()
  532. } else {
  533. client.sendResponse(r.FailReadErrorDataCmd, " ", err.Error())
  534. client.kill()
  535. }
  536. s.log().WithError(err).Warn("Error reading data")
  537. client.resetTransaction()
  538. break
  539. }
  540. res := s.backend().Process(client.Envelope)
  541. if res.Code() < 300 {
  542. client.messagesSent++
  543. }
  544. client.sendResponse(res)
  545. client.state = ClientCmd
  546. if s.isShuttingDown() {
  547. client.state = ClientShutdown
  548. }
  549. client.resetTransaction()
  550. case ClientStartTLS:
  551. if !client.TLS && sc.TLS.StartTLSOn {
  552. tlsConfig, ok := s.tlsConfigStore.Load().(*tls.Config)
  553. if !ok {
  554. s.mainlog().Error("Failed to load *tls.Config")
  555. } else if err := client.upgradeToTLS(tlsConfig); err == nil {
  556. advertiseTLS = ""
  557. client.resetTransaction()
  558. } else {
  559. s.log().WithError(err).Warnf("[%s] Failed TLS handshake", client.RemoteIP)
  560. // Don't disconnect, let the client decide if it wants to continue
  561. }
  562. }
  563. // change to command state
  564. client.state = ClientCmd
  565. case ClientShutdown:
  566. // shutdown state
  567. client.sendResponse(r.ErrorShutdown)
  568. client.kill()
  569. }
  570. if client.bufErr != nil {
  571. s.log().WithError(client.bufErr).Debug("client could not buffer a response")
  572. return
  573. }
  574. // flush the response buffer
  575. if client.bufout.Buffered() > 0 {
  576. if s.log().IsDebug() {
  577. s.log().Debugf("Writing response to client: \n%s", client.response.String())
  578. }
  579. err := s.flushResponse(client)
  580. if err != nil {
  581. s.log().WithError(err).Debug("error writing response")
  582. return
  583. }
  584. }
  585. }
  586. }
  587. func (s *server) log() log.Logger {
  588. return s.loadLog(&s.logStore)
  589. }
  590. func (s *server) mainlog() log.Logger {
  591. return s.loadLog(&s.mainlogStore)
  592. }
  593. func (s *server) loadLog(value *atomic.Value) log.Logger {
  594. if l, ok := value.Load().(log.Logger); ok {
  595. return l
  596. }
  597. out := log.OutputStderr.String()
  598. level := log.InfoLevel.String()
  599. if value == &s.logStore {
  600. if sc, ok := s.configStore.Load().(ServerConfig); ok && sc.LogFile != "" {
  601. out = sc.LogFile
  602. }
  603. level = s.mainlog().GetLevel()
  604. }
  605. l, err := log.GetLogger(out, level)
  606. if err == nil {
  607. value.Store(l)
  608. }
  609. return l
  610. }
  611. // defaultHost ensures that the host attribute is set, if addressed to Postmaster
  612. func (s *server) defaultHost(a *mail.Address) {
  613. if a.Host == "" && a.IsPostmaster() {
  614. sc := s.configStore.Load().(ServerConfig)
  615. a.Host = sc.Hostname
  616. if !s.allowsHost(a.Host) {
  617. s.log().WithFields(
  618. logrus.Fields{"hostname": sc.Hostname}).
  619. Warn("the hostname is not present in AllowedHosts config setting")
  620. }
  621. }
  622. }