@marcel91200 / caddy Mirror · read-only
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 01:00 UTC

master
go 455 lines 10.1 KB
Raw
1 // Copyright 2015 Matthew Holt and The Caddy Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package caddytls
16
17 import (
18 "context"
19 "crypto/tls"
20 "encoding/json"
21 "net"
22 "testing"
23
24 "github.com/caddyserver/caddy/v2"
25 "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
26 )
27
28 func TestServerNameMatcher(t *testing.T) {
29 for i, tc := range []struct {
30 names []string
31 input string
32 expect bool
33 }{
34 {
35 names: []string{"example.com"},
36 input: "example.com",
37 expect: true,
38 },
39 {
40 names: []string{"example.com"},
41 input: "foo.com",
42 expect: false,
43 },
44 {
45 names: []string{"example.com"},
46 input: "",
47 expect: false,
48 },
49 {
50 names: []string{},
51 input: "",
52 expect: false,
53 },
54 {
55 names: []string{"foo", "example.com"},
56 input: "example.com",
57 expect: true,
58 },
59 {
60 names: []string{"foo", "example.com"},
61 input: "sub.example.com",
62 expect: false,
63 },
64 {
65 names: []string{"foo", "example.com"},
66 input: "foo.com",
67 expect: false,
68 },
69 {
70 names: []string{"*.example.com"},
71 input: "example.com",
72 expect: false,
73 },
74 {
75 names: []string{"*.example.com"},
76 input: "sub.example.com",
77 expect: true,
78 },
79 {
80 names: []string{"*.example.com", "*.sub.example.com"},
81 input: "sub2.sub.example.com",
82 expect: true,
83 },
84 {
85 names: []string{"つ.localhost"},
86 input: "xn--k9j.localhost",
87 expect: true,
88 },
89 {
90 names: []string{"つ.Localhost"},
91 input: "XN--K9J.LOCALHOST",
92 expect: true,
93 },
94 {
95 names: []string{"*.つ.localhost"},
96 input: "sub.xn--k9j.localhost",
97 expect: true,
98 },
99 {
100 names: []string{"*.つ.Localhost"},
101 input: "Sub.XN--K9J.LOCALHOST",
102 expect: true,
103 },
104 } {
105 chi := &tls.ClientHelloInfo{ServerName: tc.input}
106 actual := MatchServerName(tc.names).Match(chi)
107 if actual != tc.expect {
108 t.Errorf("Test %d: Expected %t but got %t (input=%s match=%v)",
109 i, tc.expect, actual, tc.input, tc.names)
110 }
111 }
112 }
113
114 func TestServerNameREMatcher(t *testing.T) {
115 for i, tc := range []struct {
116 pattern string
117 input string
118 expect bool
119 }{
120 {
121 pattern: "^example\\.(com|net)$",
122 input: "example.com",
123 expect: true,
124 },
125 {
126 pattern: "^example\\.(com|net)$",
127 input: "foo.com",
128 expect: false,
129 },
130 {
131 pattern: "^example\\.(com|net)$",
132 input: "",
133 expect: false,
134 },
135 {
136 pattern: "",
137 input: "",
138 expect: true,
139 },
140 {
141 pattern: "^example\\.(com|net)$",
142 input: "foo.example.com",
143 expect: false,
144 },
145 } {
146 chi := &tls.ClientHelloInfo{ServerName: tc.input}
147 mre := MatchServerNameRE{MatchRegexp{Pattern: tc.pattern}}
148 ctx, _ := caddy.NewContext(caddy.Context{Context: context.Background()})
149 if mre.Provision(ctx) != nil {
150 t.Errorf("Test %d: Failed to provision a regexp matcher (pattern=%v)", i, tc.pattern)
151 }
152 actual := mre.Match(chi)
153 if actual != tc.expect {
154 t.Errorf("Test %d: Expected %t but got %t (input=%s match=%v)",
155 i, tc.expect, actual, tc.input, tc.pattern)
156 }
157 }
158 }
159
160 func TestRemoteIPMatcher(t *testing.T) {
161 ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
162 defer cancel()
163
164 for i, tc := range []struct {
165 ranges []string
166 notRanges []string
167 input string
168 expect bool
169 }{
170 {
171 ranges: []string{"127.0.0.1"},
172 input: "127.0.0.1:12345",
173 expect: true,
174 },
175 {
176 ranges: []string{"127.0.0.1"},
177 input: "127.0.0.2:12345",
178 expect: false,
179 },
180 {
181 ranges: []string{"127.0.0.1/16"},
182 input: "127.0.1.23:12345",
183 expect: true,
184 },
185 {
186 ranges: []string{"127.0.0.1", "192.168.1.105"},
187 input: "192.168.1.105:12345",
188 expect: true,
189 },
190 {
191 notRanges: []string{"127.0.0.1"},
192 input: "127.0.0.1:12345",
193 expect: false,
194 },
195 {
196 notRanges: []string{"127.0.0.2"},
197 input: "127.0.0.1:12345",
198 expect: true,
199 },
200 {
201 ranges: []string{"127.0.0.1"},
202 notRanges: []string{"127.0.0.2"},
203 input: "127.0.0.1:12345",
204 expect: true,
205 },
206 {
207 ranges: []string{"127.0.0.2"},
208 notRanges: []string{"127.0.0.2"},
209 input: "127.0.0.2:12345",
210 expect: false,
211 },
212 {
213 ranges: []string{"127.0.0.2"},
214 notRanges: []string{"127.0.0.2"},
215 input: "127.0.0.3:12345",
216 expect: false,
217 },
218 } {
219 matcher := MatchRemoteIP{Ranges: tc.ranges, NotRanges: tc.notRanges}
220 err := matcher.Provision(ctx)
221 if err != nil {
222 t.Fatalf("Test %d: Provision failed: %v", i, err)
223 }
224
225 addr := testAddr(tc.input)
226 chi := &tls.ClientHelloInfo{Conn: testConn{addr: addr}}
227
228 actual := matcher.Match(chi)
229 if actual != tc.expect {
230 t.Errorf("Test %d: Expected %t but got %t (input=%s ranges=%v notRanges=%v)",
231 i, tc.expect, actual, tc.input, tc.ranges, tc.notRanges)
232 }
233 }
234 }
235
236 func TestLocalIPMatcher(t *testing.T) {
237 ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
238 defer cancel()
239
240 for i, tc := range []struct {
241 ranges []string
242 input string
243 expect bool
244 }{
245 {
246 ranges: []string{"127.0.0.1"},
247 input: "127.0.0.1:12345",
248 expect: true,
249 },
250 {
251 ranges: []string{"127.0.0.1"},
252 input: "127.0.0.2:12345",
253 expect: false,
254 },
255 {
256 ranges: []string{"127.0.0.1/16"},
257 input: "127.0.1.23:12345",
258 expect: true,
259 },
260 {
261 ranges: []string{"127.0.0.1", "192.168.1.105"},
262 input: "192.168.1.105:12345",
263 expect: true,
264 },
265 {
266 input: "127.0.0.1:12345",
267 expect: true,
268 },
269 {
270 ranges: []string{"127.0.0.1"},
271 input: "127.0.0.1:12345",
272 expect: true,
273 },
274 {
275 ranges: []string{"127.0.0.2"},
276 input: "127.0.0.3:12345",
277 expect: false,
278 },
279 {
280 ranges: []string{"127.0.0.2"},
281 input: "127.0.0.2",
282 expect: true,
283 },
284 {
285 ranges: []string{"127.0.0.2"},
286 input: "127.0.0.300",
287 expect: false,
288 },
289 } {
290 matcher := MatchLocalIP{Ranges: tc.ranges}
291 err := matcher.Provision(ctx)
292 if err != nil {
293 t.Fatalf("Test %d: Provision failed: %v", i, err)
294 }
295
296 addr := testAddr(tc.input)
297 chi := &tls.ClientHelloInfo{Conn: testConn{addr: addr}}
298
299 actual := matcher.Match(chi)
300 if actual != tc.expect {
301 t.Errorf("Test %d: Expected %t but got %t (input=%s ranges=%v)",
302 i, tc.expect, actual, tc.input, tc.ranges)
303 }
304 }
305 }
306
307 func TestNotMatcher(t *testing.T) {
308 ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
309 defer cancel()
310
311 for i, tc := range []struct {
312 config string
313 serverName string
314 input string
315 expect bool
316 }{
317 {
318 config: `[]`,
319 input: "10.1.2.3:12345",
320 expect: true,
321 },
322 {
323 config: `[{"local_ip": {"ranges": ["10.1.2.3"]}}]`,
324 input: "10.1.2.3:12345",
325 expect: false,
326 },
327 {
328 config: `[{"local_ip": {"ranges": ["10.1.2.3"]}}]`,
329 input: "10.2.3.4:12345",
330 expect: true,
331 },
332 {
333 config: `[{"remote_ip": {"ranges": ["10.0.0.0/8"]}, "sni": ["example.com"]}]`,
334 serverName: "example.com",
335 input: "10.1.2.3:12345",
336 expect: false,
337 },
338 {
339 config: `[{"remote_ip": {"ranges": ["10.0.0.0/8"]}, "sni": ["example.com"]}]`,
340 serverName: "example.net",
341 input: "10.1.2.3:12345",
342 expect: true,
343 },
344 {
345 config: `[{"remote_ip": {"ranges": ["10.0.0.0/8"]}}, {"sni": ["example.com"]}]`,
346 serverName: "example.com",
347 input: "192.168.1.1:12345",
348 expect: false,
349 },
350 {
351 config: `[{"remote_ip": {"ranges": ["10.0.0.0/8"]}}, {"sni": ["example.com"]}]`,
352 serverName: "example.net",
353 input: "192.168.1.1:12345",
354 expect: true,
355 },
356 {
357 config: `[{"not": [{"remote_ip": {"ranges": ["10.0.0.0/8"]}}]}]`,
358 input: "10.1.2.3:12345",
359 expect: true,
360 },
361 } {
362 var matcher MatchNot
363 if err := json.Unmarshal([]byte(tc.config), &matcher); err != nil {
364 t.Fatalf("Test %d: unmarshaling config: %v", i, err)
365 }
366 if err := matcher.Provision(ctx); err != nil {
367 t.Fatalf("Test %d: Provision failed: %v", i, err)
368 }
369
370 addr := testAddr(tc.input)
371 chi := &tls.ClientHelloInfo{ServerName: tc.serverName, Conn: testConn{addr: addr}}
372
373 actual := matcher.Match(chi)
374 if actual != tc.expect {
375 t.Errorf("Test %d: Expected %t but got %t (config=%s input=%s serverName=%s)",
376 i, tc.expect, actual, tc.config, tc.input, tc.serverName)
377 }
378 }
379 }
380
381 func TestNotMatcherUnmarshalCaddyfile(t *testing.T) {
382 for i, tc := range []struct {
383 input string
384 expect string
385 wantErr bool
386 }{
387 {
388 input: `not local_ip 10.1.2.3`,
389 expect: `[{"local_ip":{"ranges":["10.1.2.3"]}}]`,
390 },
391 {
392 input: `not {
393 remote_ip 10.0.0.0/8
394 sni example.com
395 }`,
396 expect: `[{"remote_ip":{"ranges":["10.0.0.0/8"]},"sni":["example.com"]}]`,
397 },
398 {
399 input: `not sni example.com
400 not remote_ip 10.0.0.0/8`,
401 expect: `[{"sni":["example.com"]},{"remote_ip":{"ranges":["10.0.0.0/8"]}}]`,
402 },
403 {
404 input: `not not sni example.com`,
405 expect: `[{"not":[{"sni":["example.com"]}]}]`,
406 },
407 {
408 input: `not`,
409 wantErr: true,
410 },
411 {
412 input: `not {
413 }`,
414 wantErr: true,
415 },
416 {
417 input: `not foo`,
418 wantErr: true,
419 },
420 } {
421 var matcher MatchNot
422 err := matcher.UnmarshalCaddyfile(caddyfile.NewTestDispenser(tc.input))
423 if tc.wantErr {
424 if err == nil {
425 t.Errorf("Test %d: expected error but got none", i)
426 }
427 continue
428 }
429 if err != nil {
430 t.Errorf("Test %d: unexpected error: %v", i, err)
431 continue
432 }
433
434 actual, err := json.Marshal(matcher)
435 if err != nil {
436 t.Fatalf("Test %d: marshaling matcher: %v", i, err)
437 }
438 if string(actual) != tc.expect {
439 t.Errorf("Test %d: expected %s, got %s", i, tc.expect, actual)
440 }
441 }
442 }
443
444 type testConn struct {
445 *net.TCPConn
446 addr testAddr
447 }
448
449 func (tc testConn) RemoteAddr() net.Addr { return tc.addr }
450 func (tc testConn) LocalAddr() net.Addr { return tc.addr }
451
452 type testAddr string
453
454 func (testAddr) Network() string { return "tcp" }
455 func (ta testAddr) String() string { return string(ta) }