From c3288823afda90d737b33f149c38bc180abd5381 Mon Sep 17 00:00:00 2001 From: Daniel Oaks Date: Wed, 13 Apr 2016 20:45:09 +1000 Subject: [PATCH] Add native SSL/TLS listener support from @enmand for our new config --- .gitignore | 1 + README.md | 11 +++++------ irc/config.go | 33 +++++++++++++++++++++++++++++++++ irc/server.go | 13 ++++++++++--- oragono.yaml | 8 ++++++++ 5 files changed, 57 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index b1bdee32..218707f6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /ircd.* +/ssl.* diff --git a/README.md b/README.md index a9e72c92..f6884ac5 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,13 @@ Oragono is a very early, extremely experimental fork of the [Ergonomadic](https: * channels that [persist][go-sqlite] between restarts (+P) * messages are queued in the same order to all connected clients -# What about SSL/TLS support? +# What about SSL/TLS? -Go has a not-yet-verified-as-safe TLS 1.2 implementation. Sadly, many popular -IRC clients will negotiate nothing newer than SSLv2. If you want to use SSL to -protect traffic, I recommend using +There is inbuilt TLS support using the Go TLS implementation. However, [stunnel](https://www.stunnel.org/index.html) version 4.56 with haproxy's -[PROXY protocol][proxy-proto]. This will allow the server to get the client's -original addresses for hostname lookups. +[PROXY protocol](http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt) +may also be used. This will allow the server to get the client's original +addresses for hostname lookups. # Installation diff --git a/irc/config.go b/irc/config.go index 18434cfe..0142b3fb 100644 --- a/irc/config.go +++ b/irc/config.go @@ -1,6 +1,7 @@ package irc import ( + "crypto/tls" "errors" "io/ioutil" "log" @@ -12,6 +13,24 @@ type PassConfig struct { Password string } +// SSLListenConfig defines configuration options for listening on SSL +type SSLListenConfig struct { + Cert string + Key string +} + +// Certificate returns the SSL certificate assicated with this SSLListenConfig +func (conf *SSLListenConfig) Config() (*tls.Config, error) { + cert, err := tls.LoadX509KeyPair(conf.Cert, conf.Key) + if err != nil { + return nil, errors.New("ssl cert+key: invalid pair") + } + + return &tls.Config{ + Certificates: []tls.Certificate{cert}, + }, err +} + func (conf *PassConfig) PasswordBytes() []byte { bytes, err := DecodePassword(conf.Password) if err != nil { @@ -35,6 +54,8 @@ type Config struct { MOTD string } + SSLListener map[string]*SSLListenConfig + Operator map[string]*PassConfig Theater map[string]*PassConfig @@ -60,6 +81,18 @@ func (conf *Config) Theaters() map[Name][]byte { return theaters } +func (conf *Config) SSLListeners() map[Name]*tls.Config { + sslListeners := make(map[Name]*tls.Config) + for s, sslListenersConf := range conf.SSLListener { + config, err := sslListenersConf.Config() + if err != nil { + log.Fatal(err) + } + sslListeners[NewName(s)] = config + } + return sslListeners +} + func LoadConfig(filename string) (config *Config, err error) { data, err := ioutil.ReadFile(filename) if err != nil { diff --git a/irc/server.go b/irc/server.go index f6e4bb91..3e77511e 100644 --- a/irc/server.go +++ b/irc/server.go @@ -2,6 +2,7 @@ package irc import ( "bufio" + "crypto/tls" "database/sql" "fmt" "log" @@ -88,7 +89,7 @@ func NewServer(config *Config) *Server { server.loadChannels() for _, addr := range config.Server.Listen { - server.listen(addr) + server.listen(addr, config.SSLListeners()) } if config.Server.Wslisten != "" { @@ -223,13 +224,18 @@ func (server *Server) Run() { // listen goroutine // -func (s *Server) listen(addr string) { +func (s *Server) listen(addr string, ssl map[Name]*tls.Config) { + config, listenSSL := ssl[NewName(addr)] + listener, err := net.Listen("tcp", addr) if err != nil { log.Fatal(s, "listen error: ", err) } - Log.info.Printf("%s listening on %s", s, addr) + if listenSSL { + listener = tls.NewListener(listener, config) + } + Log.info.Printf("%s listening on %s. ssl: %t", s, addr, listenSSL) go func() { for { @@ -250,6 +256,7 @@ func (s *Server) listen(addr string) { // func (s *Server) wslisten(addr string) { + //TODO(dan): open a https websocket here if ssl/tls details are setup in the config for the wslistener http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { Log.error.Printf("%s method not allowed", s) diff --git a/oragono.yaml b/oragono.yaml index c3ab2116..f3de0013 100644 --- a/oragono.yaml +++ b/oragono.yaml @@ -18,6 +18,7 @@ server: - ":6667" - "127.0.0.1:6668" - "[::1]:6668" + - ":6697" # ssl port # websocket listening port wslisten: ":8080" @@ -33,6 +34,13 @@ server: # if you change the motd, you should move it to ircd.motd motd: oragono.motd +# ssl listeners +ssllistener: + # listener on ":6697" + ":6697": + key: ssl.key + cert: ssl.crt + # ircd operators operator: # operator named 'dan'