-
Notifications
You must be signed in to change notification settings - Fork 11
/
plugin.go
188 lines (157 loc) · 5.4 KB
/
plugin.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package netserver
import (
"fmt"
"log"
"strings"
"github.com/caddyserver/caddy"
"github.com/caddyserver/caddy/caddyfile"
"github.com/caddyserver/caddy/caddytls"
)
const serverType = "net"
// directives for the net server type
// The ordering of this list is important, host need to be called before
// tls to get the relevant hostname needed
var directives = []string{"host", "tls"}
func init() {
caddy.RegisterServerType(serverType, caddy.ServerType{
Directives: func() []string { return directives },
DefaultInput: func() caddy.Input {
return caddy.CaddyfileInput{
ServerTypeName: serverType,
}
},
NewContext: newContext,
})
caddy.RegisterParsingCallback(serverType, "tls", activateTLS)
caddytls.RegisterConfigGetter(serverType, func(c *caddy.Controller) *caddytls.Config { return GetConfig(c).TLS })
}
func newContext(inst *caddy.Instance) caddy.Context {
return &netContext{instance: inst, keysToConfigs: make(map[string]*Config)}
}
type netContext struct {
instance *caddy.Instance
// keysToConfigs maps an address at the top of a
// server block (a "key") to its Config. Not all
// Configs will be represented here, only ones
// that appeared in the Caddyfile.
keysToConfigs map[string]*Config
// configs is the master list of all site configs.
configs []*Config
}
func (n *netContext) saveConfig(key string, cfg *Config) {
n.configs = append(n.configs, cfg)
n.keysToConfigs[key] = cfg
}
type configTokens map[string][]string
// InspectServerBlocks make sure that everything checks out before
// executing directives and otherwise prepares the directives to
// be parsed and executed.
func (n *netContext) InspectServerBlocks(sourceFile string, serverBlocks []caddyfile.ServerBlock) ([]caddyfile.ServerBlock, error) {
cfg := make(map[string]configTokens)
// Example:
// proxy :12017 :22017 {
// host localhost
// tls off
// }
// ServerBlock Keys will be proxy :12017 :22017 and Tokens will be host and tls
// For each key in each server block, make a new config
for _, sb := range serverBlocks {
// build unique key from server block keys and join with '~' i.e echo~:12345
key := ""
for _, k := range sb.Keys {
k = strings.ToLower(k)
if key == "" {
key = k
} else {
key += fmt.Sprintf("~%s", k)
}
}
if _, dup := n.keysToConfigs[key]; dup {
return serverBlocks, fmt.Errorf("duplicate key: %s", key)
}
tokens := make(map[string][]string)
for k, v := range sb.Tokens {
tokens[k] = []string{}
for _, token := range v {
tokens[k] = append(tokens[k], token.Text)
}
}
cfg[key] = tokens
}
// build the actual Config from gathered data
// key is the server block key joined by ~
// value is the tokens (NOTE: tokens are not used at the moment)
for k := range cfg {
params := strings.Split(k, "~")
listenType := params[0]
params = params[1:]
if len(params) == 0 {
return serverBlocks, fmt.Errorf("invalid configuration: %s", k)
}
if listenType == "proxy" && len(params) < 2 {
return serverBlocks, fmt.Errorf("invalid configuration: proxy server block expects a source and destination address")
}
// Make our caddytls.Config, which has a pointer to the
// instance's certificate cache
caddytlsConfig, err := caddytls.NewConfig(n.instance)
if err != nil {
return serverBlocks, fmt.Errorf("creating new TLS configuration: %v", err)
}
// Save the config to our master list, and key it for lookups
c := &Config{
TLS: caddytlsConfig,
Type: listenType,
ListenPort: params[0], // first element should always be the port
Parameters: params,
}
n.saveConfig(k, c)
}
return serverBlocks, nil
}
// MakeServers uses the newly-created configs to create and return a list of server instances.
func (n *netContext) MakeServers() ([]caddy.Server, error) {
// create servers based on config type
var servers []caddy.Server
for _, cfg := range n.configs {
switch cfg.Type {
case "echo":
s, err := NewEchoServer(cfg.Parameters[0], cfg)
if err != nil {
return nil, err
}
servers = append(servers, s)
case "proxy":
s, err := NewProxyServer(cfg.Parameters[0], cfg.Parameters[1], cfg)
if err != nil {
return nil, err
}
servers = append(servers, s)
}
}
return servers, nil
}
// GetConfig gets the Config that corresponds to c.
// If none exist (should only happen in tests), then a
// new, empty one will be created.
func GetConfig(c *caddy.Controller) *Config {
ctx := c.Context().(*netContext)
key := strings.Join(c.ServerBlockKeys, "~")
//only check for config if the value is proxy or echo
//we need to do this because we specify the ports in the server block
//and those values need to be ignored as they are also sent from caddy main process.
if strings.Contains(key, "echo") || strings.Contains(key, "proxy") {
if cfg, ok := ctx.keysToConfigs[key]; ok {
return cfg
}
}
// we should only get here if value of key in server block
// is not echo or proxy i.e port number :12017
// we can't return a nil because caddytls.RegisterConfigGetter will panic
// so we return a default (blank) config value
caddytlsConfig, err := caddytls.NewConfig(ctx.instance)
if err != nil {
log.Printf("[ERROR] Making new TLS configuration: %v", err)
return new(Config)
}
return &Config{TLS: caddytlsConfig}
}