mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-10-31 08:11:32 +01:00 
			
		
		
		
	If you had HTTPS_PROXY=https://some-valid-cert.example.com running a CONNECT proxy, we should've been able to do a TLS CONNECT request to e.g. controlplane.tailscale.com:443 through that, and I'm pretty sure it used to work, but refactorings and lack of integration tests made it regress. It probably regressed when we added the baked-in LetsEncrypt root cert validation fallback code, which was testing against the wrong hostname (the ultimate one, not the one which we were being asked to validate) Fixes #16222 Change-Id: If014e395f830e2f87f056f588edacad5c15e91bc Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
		
			
				
	
	
		
			82 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			82 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) Tailscale Inc & AUTHORS
 | |
| // SPDX-License-Identifier: BSD-3-Clause
 | |
| 
 | |
| // The proxy-test-server command is a simple HTTP proxy server for testing
 | |
| // Tailscale's client proxy functionality.
 | |
| package main
 | |
| 
 | |
| import (
 | |
| 	"crypto/tls"
 | |
| 	"flag"
 | |
| 	"fmt"
 | |
| 	"log"
 | |
| 	"net"
 | |
| 	"net/http"
 | |
| 	"os"
 | |
| 	"strings"
 | |
| 
 | |
| 	"golang.org/x/crypto/acme/autocert"
 | |
| 	"tailscale.com/net/connectproxy"
 | |
| 	"tailscale.com/tempfork/acme"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	listen            = flag.String("listen", ":8080", "Address to listen on for HTTPS proxy requests")
 | |
| 	hostname          = flag.String("hostname", "localhost", "Hostname for the proxy server")
 | |
| 	tailscaleOnly     = flag.Bool("tailscale-only", true, "Restrict proxy to Tailscale targets only")
 | |
| 	extraAllowedHosts = flag.String("allow-hosts", "", "Comma-separated list of allowed target hosts to additionally allow if --tailscale-only is true")
 | |
| )
 | |
| 
 | |
| func main() {
 | |
| 	flag.Parse()
 | |
| 
 | |
| 	am := &autocert.Manager{
 | |
| 		HostPolicy: autocert.HostWhitelist(*hostname),
 | |
| 		Prompt:     autocert.AcceptTOS,
 | |
| 		Cache:      autocert.DirCache(os.ExpandEnv("$HOME/.cache/autocert/proxy-test-server")),
 | |
| 	}
 | |
| 	var allowTarget func(hostPort string) error
 | |
| 	if *tailscaleOnly {
 | |
| 		allowTarget = func(hostPort string) error {
 | |
| 			host, port, err := net.SplitHostPort(hostPort)
 | |
| 			if err != nil {
 | |
| 				return fmt.Errorf("invalid target %q: %v", hostPort, err)
 | |
| 			}
 | |
| 			if port != "443" {
 | |
| 				return fmt.Errorf("target %q must use port 443", hostPort)
 | |
| 			}
 | |
| 			for allowed := range strings.SplitSeq(*extraAllowedHosts, ",") {
 | |
| 				if host == allowed {
 | |
| 					return nil // explicitly allowed target
 | |
| 				}
 | |
| 			}
 | |
| 			if !strings.HasSuffix(host, ".tailscale.com") {
 | |
| 				return fmt.Errorf("target %q is not a Tailscale host", hostPort)
 | |
| 			}
 | |
| 			return nil // valid Tailscale target
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	go func() {
 | |
| 		if err := http.ListenAndServe(":http", am.HTTPHandler(nil)); err != nil {
 | |
| 			log.Fatalf("autocert HTTP server failed: %v", err)
 | |
| 		}
 | |
| 	}()
 | |
| 	hs := &http.Server{
 | |
| 		Addr: *listen,
 | |
| 		Handler: &connectproxy.Handler{
 | |
| 			Check: allowTarget,
 | |
| 			Logf:  log.Printf,
 | |
| 		},
 | |
| 		TLSConfig: &tls.Config{
 | |
| 			GetCertificate: am.GetCertificate,
 | |
| 			NextProtos: []string{
 | |
| 				"http/1.1",     // enable HTTP/2
 | |
| 				acme.ALPNProto, // enable tls-alpn ACME challenges
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 	log.Printf("Starting proxy-test-server on %s (hostname: %q)\n", *listen, *hostname)
 | |
| 	log.Fatal(hs.ListenAndServeTLS("", "")) // cert and key are provided by autocert
 | |
| }
 |