mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-25 19:15:34 +00:00
net/tshttpproxy: add start of Kerberos Negotiate auth to proxies on Windows
For now only used by a new cmd/tailscale debug --get-url subcommand. Not yet wired up to the places making HTTP requests. Updates tailscale/corp#583
This commit is contained in:
parent
dd2c61a519
commit
f915ab6552
@ -6,14 +6,20 @@
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptrace"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/peterbourgon/ff/v2/ffcli"
|
"github.com/peterbourgon/ff/v2/ffcli"
|
||||||
"tailscale.com/net/interfaces"
|
"tailscale.com/net/interfaces"
|
||||||
|
"tailscale.com/net/tshttpproxy"
|
||||||
"tailscale.com/wgengine/monitor"
|
"tailscale.com/wgengine/monitor"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,13 +28,15 @@
|
|||||||
Exec: runDebug,
|
Exec: runDebug,
|
||||||
FlagSet: (func() *flag.FlagSet {
|
FlagSet: (func() *flag.FlagSet {
|
||||||
fs := flag.NewFlagSet("debug", flag.ExitOnError)
|
fs := flag.NewFlagSet("debug", flag.ExitOnError)
|
||||||
fs.BoolVar(&debugArgs.monitor, "monitor", false, "")
|
fs.BoolVar(&debugArgs.monitor, "monitor", false, "If true, run link monitor forever. Precludes all other options.")
|
||||||
|
fs.StringVar(&debugArgs.getURL, "get-url", "", "If non-empty, fetch provided URL.")
|
||||||
return fs
|
return fs
|
||||||
})(),
|
})(),
|
||||||
}
|
}
|
||||||
|
|
||||||
var debugArgs struct {
|
var debugArgs struct {
|
||||||
monitor bool
|
monitor bool
|
||||||
|
getURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDebug(ctx context.Context, args []string) error {
|
func runDebug(ctx context.Context, args []string) error {
|
||||||
@ -38,6 +46,9 @@ func runDebug(ctx context.Context, args []string) error {
|
|||||||
if debugArgs.monitor {
|
if debugArgs.monitor {
|
||||||
return runMonitor(ctx)
|
return runMonitor(ctx)
|
||||||
}
|
}
|
||||||
|
if debugArgs.getURL != "" {
|
||||||
|
return getURL(ctx, debugArgs.getURL)
|
||||||
|
}
|
||||||
return errors.New("only --monitor is available at the moment")
|
return errors.New("only --monitor is available at the moment")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,3 +75,46 @@ func runMonitor(ctx context.Context) error {
|
|||||||
log.Printf("Started link change monitor; waiting...")
|
log.Printf("Started link change monitor; waiting...")
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getURL(ctx context.Context, urlStr string) error {
|
||||||
|
if urlStr == "login" {
|
||||||
|
urlStr = "https://login.tailscale.com"
|
||||||
|
}
|
||||||
|
log.SetOutput(os.Stdout)
|
||||||
|
ctx = httptrace.WithClientTrace(ctx, &httptrace.ClientTrace{
|
||||||
|
GetConn: func(hostPort string) { log.Printf("GetConn(%q)", hostPort) },
|
||||||
|
GotConn: func(info httptrace.GotConnInfo) { log.Printf("GotConn: %+v", info) },
|
||||||
|
DNSStart: func(info httptrace.DNSStartInfo) { log.Printf("DNSStart: %+v", info) },
|
||||||
|
DNSDone: func(info httptrace.DNSDoneInfo) { log.Printf("DNSDoneInfo: %+v", info) },
|
||||||
|
TLSHandshakeStart: func() { log.Printf("TLSHandshakeStart") },
|
||||||
|
TLSHandshakeDone: func(cs tls.ConnectionState, err error) { log.Printf("TLSHandshakeDone: %+v, %v", cs, err) },
|
||||||
|
WroteRequest: func(info httptrace.WroteRequestInfo) { log.Printf("WroteRequest: %+v", info) },
|
||||||
|
})
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", urlStr, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("http.NewRequestWithContext: %v", err)
|
||||||
|
}
|
||||||
|
proxyURL, err := tshttpproxy.ProxyFromEnvironment(req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("tshttpproxy.ProxyFromEnvironment: %v", err)
|
||||||
|
}
|
||||||
|
log.Printf("proxy: %v", proxyURL)
|
||||||
|
tr := &http.Transport{
|
||||||
|
Proxy: func(*http.Request) (*url.URL, error) { return proxyURL, nil },
|
||||||
|
ProxyConnectHeader: http.Header{},
|
||||||
|
DisableKeepAlives: true,
|
||||||
|
}
|
||||||
|
if proxyURL != nil {
|
||||||
|
auth, err := tshttpproxy.GetAuthHeader(proxyURL)
|
||||||
|
log.Printf("tshttpproxy.GetAuthHeader(%v) = %q, %v", proxyURL, auth, err)
|
||||||
|
if err == nil && auth != "" {
|
||||||
|
tr.ProxyConnectHeader.Set("Authorization", auth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res, err := tr.RoundTrip(req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Transport.RoundTrip: %v", err)
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
return res.Write(os.Stdout)
|
||||||
|
}
|
||||||
|
1
go.mod
1
go.mod
@ -3,6 +3,7 @@ module tailscale.com
|
|||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect
|
||||||
github.com/apenwarr/fixconsole v0.0.0-20191012055117-5a9f6489cc29
|
github.com/apenwarr/fixconsole v0.0.0-20191012055117-5a9f6489cc29
|
||||||
github.com/coreos/go-iptables v0.4.5
|
github.com/coreos/go-iptables v0.4.5
|
||||||
|
2
go.sum
2
go.sum
@ -9,6 +9,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo
|
|||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||||
|
github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 h1:P5U+E4x5OkVEKQDklVPmzs71WM56RTTRqV4OrDC//Y4=
|
||||||
|
github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||||
github.com/apenwarr/fixconsole v0.0.0-20191012055117-5a9f6489cc29 h1:muXWUcay7DDy1/hEQWrYlBy+g0EuwT70sBHg65SeUc4=
|
github.com/apenwarr/fixconsole v0.0.0-20191012055117-5a9f6489cc29 h1:muXWUcay7DDy1/hEQWrYlBy+g0EuwT70sBHg65SeUc4=
|
||||||
|
@ -31,3 +31,13 @@ func ProxyFromEnvironment(req *http.Request) (*url.URL, error) {
|
|||||||
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sysAuthHeader func(*url.URL) (string, error)
|
||||||
|
|
||||||
|
// GetAuthHeader returns the Authorization header value to send to proxy u.
|
||||||
|
func GetAuthHeader(u *url.URL) (string, error) {
|
||||||
|
if sysAuthHeader != nil {
|
||||||
|
return sysAuthHeader(u)
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
package tshttpproxy
|
package tshttpproxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -12,6 +14,7 @@
|
|||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/alexbrainman/sspi/negotiate"
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,6 +27,7 @@
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
sysProxyFromEnv = proxyFromWinHTTP
|
sysProxyFromEnv = proxyFromWinHTTP
|
||||||
|
sysAuthHeader = sysAuthHeaderWindows
|
||||||
}
|
}
|
||||||
|
|
||||||
func proxyFromWinHTTP(req *http.Request) (*url.URL, error) {
|
func proxyFromWinHTTP(req *http.Request) (*url.URL, error) {
|
||||||
@ -144,3 +148,20 @@ func (hi winHTTPInternet) GetProxyForURL(urlStr string) (string, error) {
|
|||||||
}
|
}
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sysAuthHeaderWindows(u *url.URL) (string, error) {
|
||||||
|
spn := "HTTP/" + u.Hostname()
|
||||||
|
creds, err := negotiate.AcquireCurrentUserCredentials()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("negotiate.AcquireCurrentUserCredentials: %w", err)
|
||||||
|
}
|
||||||
|
defer creds.Release()
|
||||||
|
|
||||||
|
secCtx, token, err := negotiate.NewClientContext(creds, spn)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("negotiate.NewClientContext: %w", err)
|
||||||
|
}
|
||||||
|
defer secCtx.Release()
|
||||||
|
|
||||||
|
return "Negotiate " + base64.StdEncoding.EncodeToString(token), nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user