| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 |
- // 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
- }
|