-
Notifications
You must be signed in to change notification settings - Fork 44
/
transport.go
101 lines (83 loc) · 2.37 KB
/
transport.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: Apache-2.0
package tscaddy
// transport.go contains the Transport module.
import (
"net/http"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
"github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy"
)
func init() {
caddy.RegisterModule(&Transport{})
}
// Transport is a caddy transport that uses a tailscale node to make requests.
type Transport struct {
Name string `json:"name,omitempty"`
node *tailscaleNode
// A non-nil TLS config enables TLS.
// We do not currently use the config values for anything.
TLS *reverseproxy.TLSConfig `json:"tls,omitempty"`
}
func (t *Transport) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "http.reverse_proxy.transport.tailscale",
New: func() caddy.Module { return new(Transport) },
}
}
// UnmarshalCaddyfile populates a Transport config from a caddyfile.
//
// We only support a single token identifying the name of a node in the App config.
// For example:
//
// reverse_proxy {
// transport tailscale my-node
// }
//
// If a node name is not specified, a default name is used.
func (t *Transport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
const defaultNodeName = "caddy-proxy"
d.Next() // skip transport name
if d.NextArg() {
t.Name = d.Val()
} else {
t.Name = defaultNodeName
}
return nil
}
func (t *Transport) Provision(ctx caddy.Context) error {
var err error
t.node, err = getNode(ctx, t.Name)
return err
}
func (t *Transport) Cleanup() error {
// Decrement usage count of this node.
_, err := nodes.Delete(t.Name)
return err
}
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
if req.URL.Scheme == "" {
if t.TLSEnabled() {
req.URL.Scheme = "https"
} else {
req.URL.Scheme = "http"
}
}
return t.node.HTTPClient().Transport.RoundTrip(req)
}
// TLSEnabled returns true if TLS is enabled.
func (h Transport) TLSEnabled() bool {
return h.TLS != nil
}
// EnableTLS enables TLS on the transport.
func (h *Transport) EnableTLS(config *reverseproxy.TLSConfig) error {
h.TLS = config
return nil
}
var (
_ http.RoundTripper = (*Transport)(nil)
_ caddy.Provisioner = (*Transport)(nil)
_ caddy.CleanerUpper = (*Transport)(nil)
_ caddyfile.Unmarshaler = (*Transport)(nil)
_ reverseproxy.TLSTransport = (*Transport)(nil)
)