From c5fabe241b6363b4adedc83c98b93b0f0009f36d Mon Sep 17 00:00:00 2001 From: Philipp Klose Date: Thu, 1 Mar 2018 15:40:32 +0100 Subject: [PATCH] Revert "Add HTTP(S) dualstack support (incl. option to generate self-signed certs). #6" This reverts commit 1271cba0a3b47b5b4ca6dddabdb96ab27a62df94. --- README.md | 7 +++- cert.go | 64 ------------------------------- docs/migration.md | 7 +++- docs/testing.md | 2 +- revel.go | 54 ++++++-------------------- server.go | 96 ++++++++++++++++++++--------------------------- 6 files changed, 66 insertions(+), 164 deletions(-) delete mode 100644 cert.go diff --git a/README.md b/README.md index 5b7b69f..af6186a 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ The major changes since forking away from Revel are these: ) func main() { + port := flag.Int("p", -1, "Port to listen on (default: use mars config)") mode := flag.String("m", "prod", "Runtime mode to select (default: prod)") flag.Parse() @@ -90,7 +91,11 @@ The major changes since forking away from Revel are these: // Reads the config, sets up template loader, creates router mars.InitDefaults(mode, ".") - mars.Run() + if *port == -1 { + *port = mars.HttpPort + } + + mars.Run(*port) } ``` 7. Run `go generate && go build && ./myapp` and be happy. diff --git a/cert.go b/cert.go deleted file mode 100644 index f451b29..0000000 --- a/cert.go +++ /dev/null @@ -1,64 +0,0 @@ -package mars - -import ( - "bytes" - "crypto/rand" - "crypto/rsa" - "crypto/tls" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "math/big" - "net" - "strings" - "time" -) - -func createCertificate(organization, domainNames string) (tls.Certificate, error) { - INFO.Printf("Creating self-signed TLS certificate for %s\n", organization) - priv, err := rsa.GenerateKey(rand.Reader, 2048) - if err != nil { - ERROR.Fatalf("Failed to generate private key: %s", err) - } - - serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) - serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) - if err != nil { - ERROR.Fatalf("failed to generate serial number: %s", err) - } - - template := x509.Certificate{ - SerialNumber: serialNumber, - Subject: pkix.Name{ - Organization: []string{organization}, - }, - NotBefore: time.Now(), - NotAfter: time.Now().Add(10 * 365 * 24 * time.Hour), - - IsCA: true, - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - } - - hosts := strings.Split(strings.TrimSpace(strings.Replace(domainNames, ",", " ", -1)), " ") - for _, h := range hosts { - if ip := net.ParseIP(h); ip != nil { - template.IPAddresses = append(template.IPAddresses, ip) - } else { - template.DNSNames = append(template.DNSNames, h) - } - } - - derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) - if err != nil { - ERROR.Fatalf("Failed to create certificate: %s", err) - } - cert := &bytes.Buffer{} - pem.Encode(cert, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) - - key := &bytes.Buffer{} - pem.Encode(key, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}) - - return tls.X509KeyPair(cert.Bytes(), key.Bytes()) -} diff --git a/docs/migration.md b/docs/migration.md index a1c75d1..a0f2098 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -34,6 +34,7 @@ ) func main() { + port := flag.Int("p", -1, "Port to listen on (default: use mars config)") mode := flag.String("m", "prod", "Runtime mode to select (default: prod)") flag.Parse() @@ -53,6 +54,10 @@ // Reads the config, sets up template loader, creates router mars.InitDefaults(mode, ".") - mars.Run() + if *port == -1 { + *port = mars.HttpPort + } + + mars.Run(*port) } 7. Run `go generate && go build && ./myapp` and be happy. diff --git a/docs/testing.md b/docs/testing.md index 2182e52..dcad2b9 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -33,7 +33,7 @@ which can be used like this: mars.InitDefaults("dev", filepath.Join(filepath.Dir(filename), "..", "..")) mars.DevMode = true - go mars.Run() + go mars.Run(0) time.Sleep(1 * time.Second) } diff --git a/revel.go b/revel.go index f4c35d3..adfa3c7 100644 --- a/revel.go +++ b/revel.go @@ -1,7 +1,6 @@ package mars import ( - "fmt" "io" "io/ioutil" "log" @@ -56,16 +55,11 @@ var ( // the current process reality. For example, if the app is configured for // port 9000, HttpPort will always be 9000, even though in dev mode it is // run on a random port and proxied. - HttpAddr = ":9000" // e.g. "", "127.0.0.1" - HttpSsl = false // e.g. true if using ssl - HttpSslCert = "" // e.g. "/path/to/cert.pem" - HttpSslKey = "" // e.g. "/path/to/key.pem" - - DualStackHTTP = false - SSLAddr = ":https" - SelfSignedCert = false - SelfSignedOrganization = "ACME Inc." - SelfSignedDomains = "127.0.0.1" + HttpPort = 9000 + HttpAddr = "" // e.g. "", "127.0.0.1" + HttpSsl = false // e.g. true if using ssl + HttpSslCert = "" // e.g. "/path/to/cert.pem" + HttpSslKey = "" // e.g. "/path/to/key.pem" // All cookies dropped by the framework begin with this prefix. CookiePrefix = "MARS" @@ -150,42 +144,18 @@ func InitDefaults(mode, basePath string) { // Configure properties from app.conf DevMode = Config.BoolDefault("mode.dev", DevMode) + HttpPort = Config.IntDefault("http.port", HttpPort) HttpAddr = Config.StringDefault("http.addr", HttpAddr) - HttpSsl = Config.BoolDefault("https.enabled", Config.BoolDefault("http.ssl", HttpSsl)) - HttpSslCert = Config.StringDefault("https.certfile", Config.StringDefault("http.sslcert", HttpSslCert)) - HttpSslKey = Config.StringDefault("https.keyfile", Config.StringDefault("http.sslkey", HttpSslKey)) - - DualStackHTTP = Config.BoolDefault("http.dualstack", DualStackHTTP) - SSLAddr = Config.StringDefault("https.addr", "") - SelfSignedCert = Config.BoolDefault("https.selfsign", SelfSignedCert) - SelfSignedOrganization = Config.StringDefault("https.organization", SelfSignedOrganization) - SelfSignedDomains = Config.StringDefault("https.domains", SelfSignedDomains) + HttpSsl = Config.BoolDefault("http.ssl", HttpSsl) + HttpSslCert = Config.StringDefault("http.sslcert", HttpSslCert) + HttpSslKey = Config.StringDefault("http.sslkey", HttpSslKey) - if (DualStackHTTP || HttpSsl) && !SelfSignedCert { + if HttpSsl { if HttpSslCert == "" { - log.Fatalln("No https.certfile provided and https.selfsign not true.") + log.Fatalln("No http.sslcert provided.") } if HttpSslKey == "" { - log.Fatalln("No https.keyfile provided and https.selfsign not true.") - } - } - - tryAddingSSLPort := false - // Support legacy way of specifying HTTPS addr - if SSLAddr == "" { - if HttpSsl && !DualStackHTTP { - SSLAddr = HttpAddr - tryAddingSSLPort = true - } else { - SSLAddr = ":https" - } - } - - // Support legacy way of specifying port number as config setting http.port - if p := Config.IntDefault("http.port", -1); p != -1 { - HttpAddr = fmt.Sprintf("%s:%d", HttpAddr, p) - if tryAddingSSLPort { - SSLAddr = fmt.Sprintf("%s:%d", SSLAddr, p) + log.Fatalln("No http.sslkey provided.") } } diff --git a/server.go b/server.go index b03b300..405a0aa 100644 --- a/server.go +++ b/server.go @@ -1,10 +1,12 @@ package mars import ( - "crypto/tls" + "fmt" "io" + "net" "net/http" - "sync" + "strconv" + "strings" "time" "golang.org/x/net/websocket" @@ -15,7 +17,6 @@ var ( MainTemplateLoader *TemplateLoader MainWatcher *Watcher Server *http.Server - SecureServer *http.Server ) // Handler is a http.HandlerFunc which exposes Mars' filtering, routing, and @@ -62,69 +63,54 @@ func handleInternal(w http.ResponseWriter, r *http.Request, ws *websocket.Conn) } } -func makeServer(addr string) *http.Server { - return &http.Server{ - Addr: addr, - Handler: Handler, - ReadTimeout: time.Duration(Config.IntDefault("timeout.read", 0)) * time.Second, - WriteTimeout: time.Duration(Config.IntDefault("timeout.write", 0)) * time.Second, +// Run the server. +// This is called from the generated main file. +// If port is non-zero, use that. Else, read the port from app.conf. +func Run(port int) { + address := HttpAddr + if port == 0 { + port = HttpPort } -} - -func Run() { - wg := sync.WaitGroup{} - if !HttpSsl || DualStackHTTP { - go func() { - time.Sleep(100 * time.Millisecond) - INFO.Printf("Listening on %s (HTTP) ...\n", HttpAddr) - }() + var network = "tcp" + var localAddress string - wg.Add(1) - go func() { - defer wg.Done() - - Server = makeServer(HttpAddr) - ERROR.Fatalln("Failed to serve:", Server.ListenAndServe()) - }() + // If the port is zero, treat the address as a fully qualified local address. + // This address must be prefixed with the network type followed by a colon, + // e.g. unix:/tmp/app.socket or tcp6:::1 (equivalent to tcp6:0:0:0:0:0:0:0:1) + if port == 0 { + parts := strings.SplitN(address, ":", 2) + network = parts[0] + localAddress = parts[1] + } else { + localAddress = address + ":" + strconv.Itoa(port) } - if HttpSsl || DualStackHTTP { - go func() { - time.Sleep(100 * time.Millisecond) - INFO.Printf("Listening on %s (HTTPS) ...\n", SSLAddr) - }() - - wg.Add(1) - go func() { - defer wg.Done() - - serveTLS(SSLAddr) - }() + Server = &http.Server{ + Addr: localAddress, + Handler: Handler, + ReadTimeout: time.Duration(Config.IntDefault("timeout.read", 0)) * time.Second, + WriteTimeout: time.Duration(Config.IntDefault("timeout.write", 0)) * time.Second, } - wg.Wait() -} - -func serveTLS(addr string) { - SecureServer = makeServer(addr) + go func() { + time.Sleep(100 * time.Millisecond) + fmt.Printf("Listening on %s...\n", localAddress) + }() - SecureServer.TLSConfig = &tls.Config{ - Certificates: make([]tls.Certificate, 1), - } - if SelfSignedCert { - keypair, err := createCertificate(SelfSignedOrganization, SelfSignedDomains) - if err != nil { - ERROR.Fatalln("Unable to create key pair:", err) + if HttpSsl { + if network != "tcp" { + // This limitation is just to reduce complexity, since it is standard + // to terminate SSL upstream when using unix domain sockets. + ERROR.Fatalln("SSL is only supported for TCP sockets. Specify a port to listen on.") } - SecureServer.TLSConfig.Certificates[0] = keypair + ERROR.Fatalln("Failed to listen:", + Server.ListenAndServeTLS(HttpSslCert, HttpSslKey)) } else { - keypair, err := tls.LoadX509KeyPair(HttpSslCert, HttpSslKey) + listener, err := net.Listen(network, localAddress) if err != nil { - ERROR.Fatalln("Unable to load key pair:", err) + ERROR.Fatalln("Failed to listen:", err) } - SecureServer.TLSConfig.Certificates[0] = keypair + ERROR.Fatalln("Failed to serve:", Server.Serve(listener)) } - - ERROR.Fatalln("Failed to serve:", SecureServer.ListenAndServeTLS("", "")) }