3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-11-29 07:29:31 +01:00

new format for listener section

This commit is contained in:
Shivaram Lingamneni 2019-06-28 10:45:34 -04:00
parent cfe991a335
commit eee0747e5e
4 changed files with 157 additions and 86 deletions

View File

@ -41,6 +41,12 @@ type TLSListenConfig struct {
Key string Key string
} }
// This is the YAML-deserializable type of the value of the `Server.Listeners` map
type listenerConfigBlock struct {
TLS TLSListenConfig
Tor bool
}
// listenerConfig is the config governing a particular listener (bound address), // listenerConfig is the config governing a particular listener (bound address),
// in particular whether it has TLS or Tor (or both) enabled. // in particular whether it has TLS or Tor (or both) enabled.
type listenerConfig struct { type listenerConfig struct {
@ -252,7 +258,7 @@ type FakelagConfig struct {
} }
type TorListenersConfig struct { type TorListenersConfig struct {
Listeners []string Listeners []string // legacy only
RequireSasl bool `yaml:"require-sasl"` RequireSasl bool `yaml:"require-sasl"`
Vhost string Vhost string
MaxConnections int `yaml:"max-connections"` MaxConnections int `yaml:"max-connections"`
@ -271,11 +277,15 @@ type Config struct {
passwordBytes []byte passwordBytes []byte
Name string Name string
nameCasefolded string nameCasefolded string
Listen []string // Listeners is the new style for configuring listeners:
Listeners map[string]listenerConfigBlock
UnixBindMode os.FileMode `yaml:"unix-bind-mode"` UnixBindMode os.FileMode `yaml:"unix-bind-mode"`
TLSListeners map[string]TLSListenConfig `yaml:"tls-listeners"`
TorListeners TorListenersConfig `yaml:"tor-listeners"` TorListeners TorListenersConfig `yaml:"tor-listeners"`
listeners map[string]listenerConfig // Listen and TLSListeners are the legacy style:
Listen []string
TLSListeners map[string]TLSListenConfig `yaml:"tls-listeners"`
// either way, the result is this:
trueListeners map[string]listenerConfig
STS STSConfig STS STSConfig
CheckIdent bool `yaml:"check-ident"` CheckIdent bool `yaml:"check-ident"`
MOTD string MOTD string
@ -481,37 +491,63 @@ func (conf *Config) Operators(oc map[string]*OperClass) (map[string]*Oper, error
return operators, nil return operators, nil
} }
// prepareListeners populates Config.Server.listeners func loadTlsConfig(config TLSListenConfig) (tlsConfig *tls.Config, err error) {
cert, err := tls.LoadX509KeyPair(config.Cert, config.Key)
if err != nil {
return nil, ErrInvalidCertKeyPair
}
result := tls.Config{
Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequestClientCert,
}
return &result, nil
}
// prepareListeners populates Config.Server.trueListeners
func (conf *Config) prepareListeners() (err error) { func (conf *Config) prepareListeners() (err error) {
listeners := make(map[string]listenerConfig)
if 0 < len(conf.Server.Listeners) {
for addr, block := range conf.Server.Listeners {
var lconf listenerConfig
lconf.IsTor = block.Tor
if block.TLS.Cert != "" {
tlsConfig, err := loadTlsConfig(block.TLS)
if err != nil {
return err
}
lconf.TLSConfig = tlsConfig
}
listeners[addr] = lconf
}
} else if 0 < len(conf.Server.Listen) {
log.Printf("WARNING: configuring listeners via the legacy `server.listen` config option")
log.Printf("This will be removed in a later release: you should update to use `server.listeners`")
torListeners := make(map[string]bool, len(conf.Server.TorListeners.Listeners)) torListeners := make(map[string]bool, len(conf.Server.TorListeners.Listeners))
for _, addr := range conf.Server.TorListeners.Listeners { for _, addr := range conf.Server.TorListeners.Listeners {
torListeners[addr] = true torListeners[addr] = true
} }
conf.Server.listeners = make(map[string]listenerConfig, len(conf.Server.Listen))
for _, addr := range conf.Server.Listen { for _, addr := range conf.Server.Listen {
var lconf listenerConfig var lconf listenerConfig
lconf.IsTor = torListeners[addr] lconf.IsTor = torListeners[addr]
tlsListenConf, ok := conf.Server.TLSListeners[addr] tlsListenConf, ok := conf.Server.TLSListeners[addr]
if ok { if ok {
cert, err := tls.LoadX509KeyPair(tlsListenConf.Cert, tlsListenConf.Key) tlsConfig, err := loadTlsConfig(tlsListenConf)
if err != nil { if err != nil {
return ErrInvalidCertKeyPair return err
} }
tlsConfig := tls.Config{ lconf.TLSConfig = tlsConfig
Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequestClientCert,
} }
lconf.TLSConfig = &tlsConfig listeners[addr] = lconf
} }
conf.Server.listeners[addr] = lconf } else {
return fmt.Errorf("No listeners were configured")
} }
conf.Server.trueListeners = listeners
return nil return nil
} }
// LoadConfig loads the given YAML configuration file. // LoadRawConfig loads the config without doing any consistency checks or postprocessing
func LoadConfig(filename string) (config *Config, err error) { func LoadRawConfig(filename string) (config *Config, err error) {
data, err := ioutil.ReadFile(filename) data, err := ioutil.ReadFile(filename)
if err != nil { if err != nil {
return nil, err return nil, err
@ -521,6 +557,15 @@ func LoadConfig(filename string) (config *Config, err error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return
}
// LoadConfig loads the given YAML configuration file.
func LoadConfig(filename string) (config *Config, err error) {
config, err = LoadRawConfig(filename)
if err != nil {
return nil, err
}
config.Filename = filename config.Filename = filename
@ -536,9 +581,6 @@ func LoadConfig(filename string) (config *Config, err error) {
if config.Datastore.Path == "" { if config.Datastore.Path == "" {
return nil, ErrDatastorePathMissing return nil, ErrDatastorePathMissing
} }
if len(config.Server.Listen) == 0 {
return nil, ErrNoListenersDefined
}
//dan: automagically fix identlen until a few releases in the future (from now, 0.12.0), being a newly-introduced limit //dan: automagically fix identlen until a few releases in the future (from now, 0.12.0), being a newly-introduced limit
if config.Limits.IdentLen < 1 { if config.Limits.IdentLen < 1 {
config.Limits.IdentLen = 20 config.Limits.IdentLen = 20

View File

@ -865,7 +865,7 @@ func (server *Server) setupListeners(config *Config) (err error) {
// update or destroy all existing listeners // update or destroy all existing listeners
for addr := range server.listeners { for addr := range server.listeners {
currentListener := server.listeners[addr] currentListener := server.listeners[addr]
newConfig, stillConfigured := config.Server.listeners[addr] newConfig, stillConfigured := config.Server.trueListeners[addr]
currentListener.Lock() currentListener.Lock()
currentListener.shouldStop = !stillConfigured currentListener.shouldStop = !stillConfigured
@ -883,7 +883,11 @@ func (server *Server) setupListeners(config *Config) (err error) {
} }
// create new listeners that were not previously configured // create new listeners that were not previously configured
for newAddr, newConfig := range config.Server.listeners { numTlsListeners := 0
for newAddr, newConfig := range config.Server.trueListeners {
if newConfig.TLSConfig != nil {
numTlsListeners += 1
}
_, exists := server.listeners[newAddr] _, exists := server.listeners[newAddr]
if !exists { if !exists {
// make new listener // make new listener
@ -898,11 +902,11 @@ func (server *Server) setupListeners(config *Config) (err error) {
} }
} }
if len(config.Server.TLSListeners) == 0 { if numTlsListeners == 0 {
server.logger.Warning("server", "You are not exposing an SSL/TLS listening port. You should expose at least one port (typically 6697) to accept TLS connections") server.logger.Warning("server", "You are not exposing an SSL/TLS listening port. You should expose at least one port (typically 6697) to accept TLS connections")
} }
if config.Server.listeners[":6697"].TLSConfig == nil { if config.Server.trueListeners[":6697"].TLSConfig == nil {
server.logger.Warning("server", "Port 6697 is the standard TLS port for IRC. You should (also) expose port 6697 as a TLS port to ensure clients can connect securely") server.logger.Warning("server", "Port 6697 is the standard TLS port for IRC. You should (also) expose port 6697 as a TLS port to ensure clients can connect securely")
} }

View File

@ -39,6 +39,46 @@ func getPassword() string {
return strings.TrimSpace(text) return strings.TrimSpace(text)
} }
// implements the `oragono mkcerts` command
func doMkcerts(configFile string, quiet bool) {
config, err := irc.LoadRawConfig(configFile)
if err != nil {
log.Fatal(err)
}
if !quiet {
log.Println("making self-signed certificates")
}
certToKey := make(map[string]string)
for name, conf := range config.Server.Listeners {
if conf.TLS.Cert == "" {
continue
}
existingKey, ok := certToKey[conf.TLS.Cert]
if ok {
if existingKey == conf.TLS.Key {
continue
} else {
log.Fatal("Conflicting TLS key files for", conf.TLS.Cert)
}
}
if !quiet {
log.Printf(" making cert for %s listener\n", name)
}
host := config.Server.Name
cert, key := conf.TLS.Cert, conf.TLS.Key
err := mkcerts.CreateCert("Oragono", host, cert, key)
if err == nil {
if !quiet {
log.Printf(" Certificate created at %s : %s\n", cert, key)
}
certToKey[cert] = key
} else {
log.Fatal(" Could not create certificate:", err.Error())
}
}
}
func main() { func main() {
version := irc.SemVer version := irc.SemVer
usage := `oragono. usage := `oragono.
@ -88,11 +128,14 @@ Options:
} else if arguments["mksecret"].(bool) { } else if arguments["mksecret"].(bool) {
fmt.Println(utils.GenerateSecretKey()) fmt.Println(utils.GenerateSecretKey())
return return
} else if arguments["mkcerts"].(bool) {
doMkcerts(arguments["--conf"].(string), arguments["--quiet"].(bool))
return
} }
configfile := arguments["--conf"].(string) configfile := arguments["--conf"].(string)
config, err := irc.LoadConfig(configfile) config, err := irc.LoadConfig(configfile)
if err != nil { if err != nil && !(err == irc.ErrInvalidCertKeyPair && arguments["mkcerts"].(bool)) {
log.Fatal("Config file did not load successfully: ", err.Error()) log.Fatal("Config file did not load successfully: ", err.Error())
} }
@ -114,25 +157,6 @@ Options:
if !arguments["--quiet"].(bool) { if !arguments["--quiet"].(bool) {
log.Println("database upgraded: ", config.Datastore.Path) log.Println("database upgraded: ", config.Datastore.Path)
} }
} else if arguments["mkcerts"].(bool) {
if !arguments["--quiet"].(bool) {
log.Println("making self-signed certificates")
}
for name, conf := range config.Server.TLSListeners {
if !arguments["--quiet"].(bool) {
log.Printf(" making cert for %s listener\n", name)
}
host := config.Server.Name
err := mkcerts.CreateCert("Oragono", host, conf.Cert, conf.Key)
if err == nil {
if !arguments["--quiet"].(bool) {
log.Printf(" Certificate created at %s : %s\n", conf.Cert, conf.Key)
}
} else {
log.Fatal(" Could not create certificate:", err.Error())
}
}
} else if arguments["run"].(bool) { } else if arguments["run"].(bool) {
if !arguments["--quiet"].(bool) { if !arguments["--quiet"].(bool) {
logman.Info("server", fmt.Sprintf("Oragono v%s starting", irc.SemVer)) logman.Info("server", fmt.Sprintf("Oragono v%s starting", irc.SemVer))

View File

@ -11,14 +11,30 @@ server:
name: oragono.test name: oragono.test
# addresses to listen on # addresses to listen on
listen: listeners:
- ":6697" # SSL/TLS port # This is the standard SSL/TLS port for IRC:
- ":6667" # plaintext port ":6697":
# To disable plaintext over the Internet, comment out :6667 and replace with: tls:
# - "127.0.0.1:6667" # (loopback ipv4, localhost-only) key: tls.key
# - "[::1]:6667" # (loopback ipv6, localhost-only) cert: tls.crt
# Unix domain socket for proxying:
# - "/tmp/oragono_sock" # The standard plaintext port for IRC is 6667. Since using plaintext over
# the public Internet poses security and privacy issues, we recommend using
# plaintext only on local interfaces:
"127.0.0.1:6667": # (loopback ipv4, localhost-only)
"[::1]:6667": # (loopback ipv6, localhost-only)
# If you need to use plaintext on non-local interfaces, comment out the above
# two lines, then uncomment the following line:
# ":6667":
# Example of a Unix domain socket for proxying:
# "/tmp/oragono_sock":
# Example of a Tor listener: any connection that comes in on this listener will
# be considered a Tor connection. It is strongly recommended that this listener
# *not* be on a public interface --- it should be on 127.0.0.0/8 or unix domain:
# "/tmp/oragono_tor_sock":
# tor: true
# sets the permissions for Unix listen sockets. on a typical Linux system, # sets the permissions for Unix listen sockets. on a typical Linux system,
# the default is 0775 or 0755, which prevents other users/groups from connecting # the default is 0775 or 0755, which prevents other users/groups from connecting
@ -26,23 +42,8 @@ server:
# where anyone can connect. # where anyone can connect.
unix-bind-mode: 0777 unix-bind-mode: 0777
# tls listeners # configure the behavior of Tor listeners (ignored if you didn't enable any):
tls-listeners:
# listener on ":6697"
":6697":
key: tls.key
cert: tls.crt
# tor listeners: designate listeners for use by a tor hidden service / .onion address
# WARNING: if you are running oragono as a pure hidden service, see the
# anonymization / hardening recommendations in docs/MANUAL.md
tor-listeners: tor-listeners:
# any connections that come in on these listeners will be considered
# Tor connections. it is strongly recommended that these listeners *not*
# be on public interfaces: they should be on 127.0.0.0/8 or unix domain
listeners:
# - "/tmp/oragono_tor_sock"
# if this is true, connections from Tor must authenticate with SASL # if this is true, connections from Tor must authenticate with SASL
require-sasl: false require-sasl: false