config.go 17 KB

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