mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 21:15:39 +00:00
b0545873e5
Now that everything's just HTTP, there's no longer a need to have a header-sniffing net.Conn wraper that dispatches which route to take. Refactor to just use an http.Server earlier instead. Updates #6417 Change-Id: I12a2054db4e56f48660c46f81233db224fdc77cb Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
75 lines
2.0 KiB
Go
75 lines
2.0 KiB
Go
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
//go:build !js
|
|
|
|
package ipnserver
|
|
|
|
import (
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
|
|
"tailscale.com/logpolicy"
|
|
)
|
|
|
|
// handleProxyConnectConn handles a CONNECT request to
|
|
// log.tailscale.io (or whatever the configured log server is). This
|
|
// is intended for use by the Windows GUI client to log via when an
|
|
// exit node is in use, so the logs don't go out via the exit node and
|
|
// instead go directly, like tailscaled's. The dialer tried to do that
|
|
// in the unprivileged GUI by binding to a specific interface, but the
|
|
// "Internet Kill Switch" installed by tailscaled for exit nodes
|
|
// precludes that from working and instead the GUI fails to dial out.
|
|
// So, go through tailscaled (with a CONNECT request) instead.
|
|
func (s *Server) handleProxyConnectConn(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
if r.Method != "CONNECT" {
|
|
panic("[unexpected] miswired")
|
|
}
|
|
|
|
hostPort := r.RequestURI
|
|
logHost := logpolicy.LogHost()
|
|
allowed := net.JoinHostPort(logHost, "443")
|
|
if hostPort != allowed {
|
|
s.logf("invalid CONNECT target %q; want %q", hostPort, allowed)
|
|
http.Error(w, "Bad CONNECT target.", http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
tr := logpolicy.NewLogtailTransport(logHost)
|
|
back, err := tr.DialContext(ctx, "tcp", hostPort)
|
|
if err != nil {
|
|
s.logf("error CONNECT dialing %v: %v", hostPort, err)
|
|
http.Error(w, "Connect failure", http.StatusBadGateway)
|
|
return
|
|
}
|
|
defer back.Close()
|
|
|
|
hj, ok := w.(http.Hijacker)
|
|
if !ok {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
c, br, err := hj.Hijack()
|
|
if err != nil {
|
|
s.logf("CONNECT hijack: %v", err)
|
|
return
|
|
}
|
|
defer c.Close()
|
|
|
|
io.WriteString(c, "HTTP/1.1 200 OK\r\n\r\n")
|
|
|
|
errc := make(chan error, 2)
|
|
go func() {
|
|
_, err := io.Copy(c, back)
|
|
errc <- err
|
|
}()
|
|
go func() {
|
|
_, err := io.Copy(back, br)
|
|
errc <- err
|
|
}()
|
|
<-errc
|
|
}
|