config.go 16 KB

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