git » gofer » commit e08b049

Support systemd sockets

author Alberto Bertogli
2017-08-21 17:24:39 UTC
committer Alberto Bertogli
2017-08-21 17:24:39 UTC
parent 19a8df7d2f0f37bf931604515116d762bf9c76e3

Support systemd sockets

This patch makes gofer support sockets that are passed by systemd via
environment variables.

It allows gofer to listen on privileged ports without running as root.

To indicate this, addresses now support the form "&name" to indicate
that we should listen on the systemd-passed file descriptor "name".

gofer.conf.example +5 -0
proxy/http.go +21 -4
proxy/raw.go +6 -4

diff --git a/gofer.conf.example b/gofer.conf.example
index 2c09f9b..ea979eb 100644
--- a/gofer.conf.example
+++ b/gofer.conf.example
@@ -4,7 +4,12 @@ control_addr = "127.0.0.1:8081"
 
 # HTTP(s) proxy
 [[https]]
+
+# Address to listen on.
+# systemd socket passing is supported, use "&name" to indicate that you've set
+# up a systemd socket unit with "FileDescriptorName=name".
 addr = ":https"
+
 certs = "/etc/letsencrypt/live/"
 
 # Take the routes from the definition below as a baseline.
diff --git a/proxy/http.go b/proxy/http.go
index fe7de4c..fe338ce 100644
--- a/proxy/http.go
+++ b/proxy/http.go
@@ -1,6 +1,7 @@
 package proxy
 
 import (
+	"crypto/tls"
 	"fmt"
 	"net/http"
 	"net/http/httputil"
@@ -10,6 +11,7 @@ import (
 	"blitiri.com.ar/go/gofer/config"
 	"blitiri.com.ar/go/gofer/util"
 	"blitiri.com.ar/go/log"
+	"blitiri.com.ar/go/systemd"
 )
 
 func httpServer(conf config.HTTP) *http.Server {
@@ -36,8 +38,12 @@ func httpServer(conf config.HTTP) *http.Server {
 
 func HTTP(conf config.HTTP) {
 	srv := httpServer(conf)
-	log.Infof("HTTP proxy on %q", conf.Addr)
-	err := srv.ListenAndServe()
+	lis, err := systemd.Listen("tcp", conf.Addr)
+	if err != nil {
+		log.Fatalf("HTTP proxy error listening on %q: %v", conf.Addr, err)
+	}
+	log.Infof("HTTP proxy on %q (%q)", conf.Addr, lis.Addr())
+	err = srv.Serve(lis)
 	log.Fatalf("HTTP proxy exited: %v", err)
 }
 
@@ -50,8 +56,19 @@ func HTTPS(conf config.HTTPS) {
 		log.Fatalf("error loading certs: %v", err)
 	}
 
-	log.Infof("HTTPS proxy on %q", srv.Addr)
-	err = srv.ListenAndServeTLS("", "")
+	rawLis, err := systemd.Listen("tcp", conf.Addr)
+	if err != nil {
+		log.Fatalf("HTTPS proxy error listening on %q: %v", conf.Addr, err)
+	}
+
+	// We need to set the NextProtos manually before creating the TLS
+	// listener, the library cannot help us with this.
+	srv.TLSConfig.NextProtos = append(srv.TLSConfig.NextProtos,
+		"h2", "http/1.1")
+	lis := tls.NewListener(rawLis, srv.TLSConfig)
+
+	log.Infof("HTTPS proxy on %q (%q)", conf.Addr, lis.Addr())
+	err = srv.Serve(lis)
 	log.Fatalf("HTTPS proxy exited: %v", err)
 }
 
diff --git a/proxy/raw.go b/proxy/raw.go
index 88564a0..5a26fd2 100644
--- a/proxy/raw.go
+++ b/proxy/raw.go
@@ -8,6 +8,7 @@ import (
 	"blitiri.com.ar/go/gofer/config"
 	"blitiri.com.ar/go/gofer/util"
 	"blitiri.com.ar/go/log"
+	"blitiri.com.ar/go/systemd"
 )
 
 func Raw(conf config.Raw) {
@@ -23,15 +24,16 @@ func Raw(conf config.Raw) {
 
 	var lis net.Listener
 	if tlsConfig != nil {
-		lis, err = tls.Listen("tcp", conf.Addr, tlsConfig)
+		lis, err = systemd.Listen("tcp", conf.Addr)
+		lis = tls.NewListener(lis, tlsConfig)
 	} else {
-		lis, err = net.Listen("tcp", conf.Addr)
+		lis, err = systemd.Listen("tcp", conf.Addr)
 	}
 	if err != nil {
-		log.Fatalf("error listening: %v", err)
+		log.Fatalf("Raw proxy error listening on %q: %v", conf.Addr, err)
 	}
 
-	log.Infof("Raw proxy on %q", conf.Addr)
+	log.Infof("Raw proxy on %q (%q)", conf.Addr, lis.Addr())
 	for {
 		conn, err := lis.Accept()
 		if err != nil {