config.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. package guerrilla
  2. import (
  3. "crypto/tls"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "os"
  8. "reflect"
  9. "strings"
  10. "time"
  11. "github.com/flashmob/go-guerrilla/backends"
  12. "github.com/flashmob/go-guerrilla/log"
  13. )
  14. // AppConfig is the holder of the configuration of the app
  15. type AppConfig struct {
  16. // Servers can have one or more items.
  17. /// Defaults to 1 server listening on 127.0.0.1:2525
  18. Servers []ServerConfig `json:"servers"`
  19. // AllowedHosts lists which hosts to accept email for. Defaults to os.Hostname
  20. AllowedHosts []string `json:"allowed_hosts"`
  21. // PidFile is the path for writing out the process id. No output if empty
  22. PidFile string `json:"pid_file"`
  23. // LogFile is where the logs go. Use path to file, or "stderr", "stdout"
  24. // or "off". Default "stderr"
  25. LogFile string `json:"log_file,omitempty"`
  26. // LogLevel controls the lowest level we log.
  27. // "info", "debug", "error", "panic". Default "info"
  28. LogLevel string `json:"log_level,omitempty"`
  29. // BackendConfig configures the email envelope processing backend
  30. BackendConfig backends.BackendConfig `json:"backend_config"`
  31. }
  32. // ServerConfig specifies config options for a single server
  33. type ServerConfig struct {
  34. // TLS Configuration
  35. TLS ServerTLSConfig `json:"tls,omitempty"`
  36. // LogFile is where the logs go. Use path to file, or "stderr", "stdout" or "off".
  37. // defaults to AppConfig.Log file setting
  38. LogFile string `json:"log_file,omitempty"`
  39. // Hostname will be used in the server's reply to HELO/EHLO. If TLS enabled
  40. // make sure that the Hostname matches the cert. Defaults to os.Hostname()
  41. // Hostname will also be used to fill the 'Host' property when the "RCPT TO" address is
  42. // addressed to just <postmaster>
  43. Hostname string `json:"host_name"`
  44. // Listen interface specified in <ip>:<port> - defaults to 127.0.0.1:2525
  45. ListenInterface string `json:"listen_interface"`
  46. // MaxSize is the maximum size of an email that will be accepted for delivery.
  47. // Defaults to 10 Mebibytes
  48. MaxSize int64 `json:"max_size"`
  49. // Timeout specifies the connection timeout in seconds. Defaults to 30
  50. Timeout int `json:"timeout"`
  51. // MaxClients controls how many maximum clients we can handle at once.
  52. // Defaults to defaultMaxClients
  53. MaxClients int `json:"max_clients"`
  54. // IsEnabled set to true to start the server, false will ignore it
  55. IsEnabled bool `json:"is_enabled"`
  56. // XClientOn when using a proxy such as Nginx, XCLIENT command is used to pass the
  57. // original client's IP address & client's HELO
  58. XClientOn bool `json:"xclient_on,omitempty"`
  59. }
  60. type ServerTLSConfig struct {
  61. // TLS Protocols to use. [0] = min, [1]max
  62. // Use Go's default if empty
  63. Protocols []string `json:"protocols,omitempty"`
  64. // TLS Ciphers to use.
  65. // Use Go's default if empty
  66. Ciphers []string `json:"ciphers,omitempty"`
  67. // TLS Curves to use.
  68. // Use Go's default if empty
  69. Curves []string `json:"curves,omitempty"`
  70. // PrivateKeyFile path to cert private key in PEM format.
  71. PrivateKeyFile string `json:"private_key_file"`
  72. // PublicKeyFile path to cert (public key) chain in PEM format.
  73. PublicKeyFile string `json:"public_key_file"`
  74. // TLS Root cert authorities to use. "A PEM encoded CA's certificate file.
  75. // Defaults to system's root CA file if empty
  76. RootCAs string `json:"root_cas_file,omitempty"`
  77. // declares the policy the server will follow for TLS Client Authentication.
  78. // Use Go's default if empty
  79. ClientAuthType string `json:"client_auth_type,omitempty"`
  80. // The following used to watch certificate changes so that the TLS can be reloaded
  81. _privateKeyFileMtime int64
  82. _publicKeyFileMtime int64
  83. // controls whether the server selects the
  84. // client's most preferred cipher suite
  85. PreferServerCipherSuites bool `json:"prefer_server_cipher_suites,omitempty"`
  86. // StartTLSOn should we offer STARTTLS command. Cert must be valid.
  87. // False by default
  88. StartTLSOn bool `json:"start_tls_on,omitempty"`
  89. // AlwaysOn run this server as a pure TLS server, i.e. SMTPS
  90. AlwaysOn bool `json:"tls_always_on,omitempty"`
  91. }
  92. // https://golang.org/pkg/crypto/tls/#pkg-constants
  93. // Ciphers introduced before Go 1.7 are listed here,
  94. // ciphers since Go 1.8, see tls_go1.8.go
  95. // ....... since Go 1.13, see tls_go1.13.go
  96. var TLSCiphers = map[string]uint16{
  97. // Note: Generally avoid using CBC unless for compatibility
  98. // The following ciphersuites are not configurable for TLS 1.3
  99. // see tls_go1.13.go for a list of ciphersuites always used in TLS 1.3
  100. "TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
  101. "TLS_RSA_WITH_AES_128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA,
  102. "TLS_RSA_WITH_AES_256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
  103. "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
  104. "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
  105. "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
  106. "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
  107. "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
  108. "TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA,
  109. "TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
  110. "TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
  111. "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
  112. "TLS_ECDHE_RSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
  113. "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
  114. "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
  115. "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
  116. // see tls_go1.13 for new TLS 1.3 ciphersuites
  117. // Note that TLS 1.3 ciphersuites are not configurable
  118. }
  119. // https://golang.org/pkg/crypto/tls/#pkg-constants
  120. var TLSProtocols = map[string]uint16{
  121. "tls1.0": tls.VersionTLS10,
  122. "tls1.1": tls.VersionTLS11,
  123. "tls1.2": tls.VersionTLS12,
  124. }
  125. // https://golang.org/pkg/crypto/tls/#CurveID
  126. var TLSCurves = map[string]tls.CurveID{
  127. "P256": tls.CurveP256,
  128. "P384": tls.CurveP384,
  129. "P521": tls.CurveP521,
  130. }
  131. // https://golang.org/pkg/crypto/tls/#ClientAuthType
  132. var TLSClientAuthTypes = map[string]tls.ClientAuthType{
  133. "NoClientCert": tls.NoClientCert,
  134. "RequestClientCert": tls.RequestClientCert,
  135. "RequireAnyClientCert": tls.RequireAnyClientCert,
  136. "VerifyClientCertIfGiven": tls.VerifyClientCertIfGiven,
  137. "RequireAndVerifyClientCert": tls.RequireAndVerifyClientCert,
  138. }
  139. const defaultMaxClients = 100
  140. const defaultTimeout = 30
  141. const defaultInterface = "127.0.0.1:2525"
  142. const defaultMaxSize = int64(10 << 20) // 10 Mebibytes
  143. // Unmarshalls json data into AppConfig struct and any other initialization of the struct
  144. // also does validation, returns error if validation failed or something went wrong
  145. func (c *AppConfig) Load(jsonBytes []byte) error {
  146. err := json.Unmarshal(jsonBytes, c)
  147. if err != nil {
  148. return fmt.Errorf("could not parse config file: %s", err)
  149. }
  150. if err = c.setDefaults(); err != nil {
  151. return err
  152. }
  153. if err = c.setBackendDefaults(); err != nil {
  154. return err
  155. }
  156. // all servers must be valid in order to continue
  157. for _, server := range c.Servers {
  158. if errs := server.Validate(); errs != nil {
  159. return errs
  160. }
  161. }
  162. // read the timestamps for the TLS keys, to determine if they need to be reloaded
  163. for i := 0; i < len(c.Servers); i++ {
  164. if err := c.Servers[i].loadTlsKeyTimestamps(); err != nil {
  165. return err
  166. }
  167. }
  168. return nil
  169. }
  170. // Emits any configuration change events onto the event bus.
  171. func (c *AppConfig) EmitChangeEvents(oldConfig *AppConfig, app Guerrilla) {
  172. // has backend changed?
  173. if !reflect.DeepEqual((*c).BackendConfig, (*oldConfig).BackendConfig) {
  174. app.Publish(EventConfigBackendConfig, c)
  175. }
  176. // has config changed, general check
  177. if !reflect.DeepEqual(oldConfig, c) {
  178. app.Publish(EventConfigNewConfig, c)
  179. }
  180. // has 'allowed hosts' changed?
  181. if !reflect.DeepEqual(oldConfig.AllowedHosts, c.AllowedHosts) {
  182. app.Publish(EventConfigAllowedHosts, c)
  183. }
  184. // has pid file changed?
  185. if strings.Compare(oldConfig.PidFile, c.PidFile) != 0 {
  186. app.Publish(EventConfigPidFile, c)
  187. }
  188. // has mainlog log changed?
  189. if strings.Compare(oldConfig.LogFile, c.LogFile) != 0 {
  190. app.Publish(EventConfigLogFile, c)
  191. }
  192. // has log level changed?
  193. if strings.Compare(oldConfig.LogLevel, c.LogLevel) != 0 {
  194. app.Publish(EventConfigLogLevel, c)
  195. }
  196. // server config changes
  197. oldServers := oldConfig.getServers()
  198. for iface, newServer := range c.getServers() {
  199. // is server is in both configs?
  200. if oldServer, ok := oldServers[iface]; ok {
  201. // since old server exists in the new config, we do not track it anymore
  202. delete(oldServers, iface)
  203. // so we know the server exists in both old & new configs
  204. newServer.emitChangeEvents(oldServer, app)
  205. } else {
  206. // start new server
  207. app.Publish(EventConfigServerNew, newServer)
  208. }
  209. }
  210. // remove any servers that don't exist anymore
  211. for _, oldServer := range oldServers {
  212. app.Publish(EventConfigServerRemove, oldServer)
  213. }
  214. }
  215. // EmitLogReopen emits log reopen events using existing config
  216. func (c *AppConfig) EmitLogReopenEvents(app Guerrilla) {
  217. app.Publish(EventConfigLogReopen, c)
  218. for _, sc := range c.getServers() {
  219. app.Publish(EventConfigServerLogReopen, sc)
  220. }
  221. }
  222. // gets the servers in a map (key by interface) for easy lookup
  223. func (c *AppConfig) getServers() map[string]*ServerConfig {
  224. servers := make(map[string]*ServerConfig, len(c.Servers))
  225. for i := 0; i < len(c.Servers); i++ {
  226. servers[c.Servers[i].ListenInterface] = &c.Servers[i]
  227. }
  228. return servers
  229. }
  230. // setDefaults fills in default server settings for values that were not configured
  231. // The defaults are:
  232. // * Server listening to 127.0.0.1:2525
  233. // * use your hostname to determine your which hosts to accept email for
  234. // * 100 maximum clients
  235. // * 10MB max message size
  236. // * log to Stderr,
  237. // * log level set to "`debug`"
  238. // * timeout to 30 sec
  239. // * Backend configured with the following processors: `HeadersParser|Header|Debugger`
  240. // where it will log the received emails.
  241. func (c *AppConfig) setDefaults() error {
  242. if c.LogFile == "" {
  243. c.LogFile = log.OutputStderr.String()
  244. }
  245. if c.LogLevel == "" {
  246. c.LogLevel = "debug"
  247. }
  248. if len(c.AllowedHosts) == 0 {
  249. if h, err := os.Hostname(); err != nil {
  250. return err
  251. } else {
  252. c.AllowedHosts = append(c.AllowedHosts, h)
  253. }
  254. }
  255. h, err := os.Hostname()
  256. if err != nil {
  257. return err
  258. }
  259. if len(c.Servers) == 0 {
  260. sc := ServerConfig{}
  261. sc.LogFile = c.LogFile
  262. sc.ListenInterface = defaultInterface
  263. sc.IsEnabled = true
  264. sc.Hostname = h
  265. sc.MaxClients = defaultMaxClients
  266. sc.Timeout = defaultTimeout
  267. sc.MaxSize = defaultMaxSize
  268. c.Servers = append(c.Servers, sc)
  269. } else {
  270. // make sure each server has defaults correctly configured
  271. for i := range c.Servers {
  272. if c.Servers[i].Hostname == "" {
  273. c.Servers[i].Hostname = h
  274. }
  275. if c.Servers[i].MaxClients == 0 {
  276. c.Servers[i].MaxClients = defaultMaxClients
  277. }
  278. if c.Servers[i].Timeout == 0 {
  279. c.Servers[i].Timeout = defaultTimeout
  280. }
  281. if c.Servers[i].MaxSize == 0 {
  282. c.Servers[i].MaxSize = defaultMaxSize // 10 Mebibytes
  283. }
  284. if c.Servers[i].ListenInterface == "" {
  285. return fmt.Errorf("listen interface not specified for server at index %d", i)
  286. }
  287. if c.Servers[i].LogFile == "" {
  288. c.Servers[i].LogFile = c.LogFile
  289. }
  290. // validate the server config
  291. err = c.Servers[i].Validate()
  292. if err != nil {
  293. return err
  294. }
  295. }
  296. }
  297. return nil
  298. }
  299. // setBackendDefaults sets default values for the backend config,
  300. // if no backend config was added before starting, then use a default config
  301. // otherwise, see what required values were missed in the config and add any missing with defaults
  302. func (c *AppConfig) setBackendDefaults() error {
  303. if len(c.BackendConfig) == 0 {
  304. h, err := os.Hostname()
  305. if err != nil {
  306. return err
  307. }
  308. c.BackendConfig = backends.BackendConfig{
  309. "log_received_mails": true,
  310. "save_workers_size": 1,
  311. "save_process": "HeadersParser|Header|Debugger",
  312. "primary_mail_host": h,
  313. }
  314. } else {
  315. if _, ok := c.BackendConfig["save_process"]; !ok {
  316. c.BackendConfig["save_process"] = "HeadersParser|Header|Debugger"
  317. }
  318. if _, ok := c.BackendConfig["primary_mail_host"]; !ok {
  319. h, err := os.Hostname()
  320. if err != nil {
  321. return err
  322. }
  323. c.BackendConfig["primary_mail_host"] = h
  324. }
  325. if _, ok := c.BackendConfig["save_workers_size"]; !ok {
  326. c.BackendConfig["save_workers_size"] = 1
  327. }
  328. if _, ok := c.BackendConfig["log_received_mails"]; !ok {
  329. c.BackendConfig["log_received_mails"] = false
  330. }
  331. }
  332. return nil
  333. }
  334. // Emits any configuration change events on the server.
  335. // All events are fired and run synchronously
  336. func (sc *ServerConfig) emitChangeEvents(oldServer *ServerConfig, app Guerrilla) {
  337. // get a list of changes
  338. changes := getChanges(
  339. *oldServer,
  340. *sc,
  341. )
  342. tlsChanges := getChanges(
  343. (*oldServer).TLS,
  344. (*sc).TLS,
  345. )
  346. if len(changes) > 0 || len(tlsChanges) > 0 {
  347. // something changed in the server config
  348. app.Publish(EventConfigServerConfig, sc)
  349. }
  350. // enable or disable?
  351. if _, ok := changes["IsEnabled"]; ok {
  352. if sc.IsEnabled {
  353. app.Publish(EventConfigServerStart, sc)
  354. } else {
  355. app.Publish(EventConfigServerStop, sc)
  356. }
  357. // do not emit any more events when IsEnabled changed
  358. return
  359. }
  360. // log file change?
  361. if _, ok := changes["LogFile"]; ok {
  362. app.Publish(EventConfigServerLogFile, sc)
  363. } else {
  364. // since config file has not changed, we reload it
  365. app.Publish(EventConfigServerLogReopen, sc)
  366. }
  367. // timeout changed
  368. if _, ok := changes["Timeout"]; ok {
  369. app.Publish(EventConfigServerTimeout, sc)
  370. }
  371. // max_clients changed
  372. if _, ok := changes["MaxClients"]; ok {
  373. app.Publish(EventConfigServerMaxClients, sc)
  374. }
  375. if len(tlsChanges) > 0 {
  376. app.Publish(EventConfigServerTLSConfig, sc)
  377. }
  378. }
  379. // Loads in timestamps for the TLS keys
  380. func (sc *ServerConfig) loadTlsKeyTimestamps() error {
  381. var statErr = func(iface string, err error) error {
  382. return fmt.Errorf(
  383. "could not stat key for server [%s], %s",
  384. iface,
  385. err.Error())
  386. }
  387. if sc.TLS.PrivateKeyFile == "" {
  388. sc.TLS._privateKeyFileMtime = time.Now().Unix()
  389. return nil
  390. }
  391. if sc.TLS.PublicKeyFile == "" {
  392. sc.TLS._publicKeyFileMtime = time.Now().Unix()
  393. return nil
  394. }
  395. if info, err := os.Stat(sc.TLS.PrivateKeyFile); err == nil {
  396. sc.TLS._privateKeyFileMtime = info.ModTime().Unix()
  397. } else {
  398. return statErr(sc.ListenInterface, err)
  399. }
  400. if info, err := os.Stat(sc.TLS.PublicKeyFile); err == nil {
  401. sc.TLS._publicKeyFileMtime = info.ModTime().Unix()
  402. } else {
  403. return statErr(sc.ListenInterface, err)
  404. }
  405. return nil
  406. }
  407. // Validate validates the server's configuration.
  408. func (sc *ServerConfig) Validate() error {
  409. var errs Errors
  410. if sc.TLS.StartTLSOn || sc.TLS.AlwaysOn {
  411. if sc.TLS.PublicKeyFile == "" {
  412. errs = append(errs, errors.New("PublicKeyFile is empty"))
  413. }
  414. if sc.TLS.PrivateKeyFile == "" {
  415. errs = append(errs, errors.New("PrivateKeyFile is empty"))
  416. }
  417. if _, err := tls.LoadX509KeyPair(sc.TLS.PublicKeyFile, sc.TLS.PrivateKeyFile); err != nil {
  418. errs = append(errs, fmt.Errorf("cannot use TLS config for [%s], %v", sc.ListenInterface, err))
  419. }
  420. }
  421. if len(errs) > 0 {
  422. return errs
  423. }
  424. return nil
  425. }
  426. // Gets the timestamp of the TLS certificates. Returns a unix time of when they were last modified
  427. // when the config was read. We use this info to determine if TLS needs to be re-loaded.
  428. func (stc *ServerTLSConfig) getTlsKeyTimestamps() (int64, int64) {
  429. return stc._privateKeyFileMtime, stc._publicKeyFileMtime
  430. }
  431. // Returns value changes between struct a & struct b.
  432. // Results are returned in a map, where each key is the name of the field that was different.
  433. // a and b are struct values, must not be pointer
  434. // and of the same struct type
  435. func getChanges(a interface{}, b interface{}) map[string]interface{} {
  436. ret := make(map[string]interface{}, 5)
  437. compareWith := structtomap(b)
  438. for key, val := range structtomap(a) {
  439. if sliceOfStr, ok := val.([]string); ok {
  440. val, _ = json.Marshal(sliceOfStr)
  441. val = string(val.([]uint8))
  442. }
  443. if sliceOfStr, ok := compareWith[key].([]string); ok {
  444. compareWith[key], _ = json.Marshal(sliceOfStr)
  445. compareWith[key] = string(compareWith[key].([]uint8))
  446. }
  447. if val != compareWith[key] {
  448. ret[key] = compareWith[key]
  449. }
  450. }
  451. // detect changes to TLS keys (have the key files been modified?)
  452. if oldTLS, ok := a.(ServerTLSConfig); ok {
  453. t1, t2 := oldTLS.getTlsKeyTimestamps()
  454. if newTLS, ok := b.(ServerTLSConfig); ok {
  455. t3, t4 := newTLS.getTlsKeyTimestamps()
  456. if t1 != t3 {
  457. ret["PrivateKeyFile"] = newTLS.PrivateKeyFile
  458. }
  459. if t2 != t4 {
  460. ret["PublicKeyFile"] = newTLS.PublicKeyFile
  461. }
  462. }
  463. }
  464. return ret
  465. }
  466. // Convert fields of a struct to a map
  467. // only able to convert int, bool, slice-of-strings and string; not recursive
  468. // slices are marshal'd to json for convenient comparison later
  469. func structtomap(obj interface{}) map[string]interface{} {
  470. ret := make(map[string]interface{})
  471. v := reflect.ValueOf(obj)
  472. t := v.Type()
  473. for index := 0; index < v.NumField(); index++ {
  474. vField := v.Field(index)
  475. fName := t.Field(index).Name
  476. k := vField.Kind()
  477. switch k {
  478. case reflect.Int:
  479. fallthrough
  480. case reflect.Int64:
  481. value := vField.Int()
  482. ret[fName] = value
  483. case reflect.String:
  484. value := vField.String()
  485. ret[fName] = value
  486. case reflect.Bool:
  487. value := vField.Bool()
  488. ret[fName] = value
  489. case reflect.Slice:
  490. ret[fName] = vField.Interface().([]string)
  491. }
  492. }
  493. return ret
  494. }