@marcel91200 / caddy Mirror · read-only / commits / 4a07a5d4
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 14, 05:15 UTC

caddyfile: tls: Ensure there is always a catch-all conn policy (#3005)

If user provides their own certs or makes any hostname-specific TLS connection policy, it means that no TLS connection would be served for any other hostnames, even though you'd expect that TLS is enabled for them, too. So now we append a catch-all conn policy if none exist, which allows all ClientHellos to be matched and served. We also fix the consolidation of automation policies, which previously gobbled up automation policies without hosts in favor of automation policies with hosts. Instead of a host-specific policy eating up an identical catch-all policy, the catch-all policy eats up the identical host-specific policy, ensuring that the policy is applied to all hosts which need it. See also: https://caddy.community/t/v2-automatic-https-certificate-errors/6847/9?u=matt

Matthew Holt committed Feb 6, 2020 at 13:00 UTC 4a07a5d41e0f54d1a1ec998b9d956ccf2a880d90
3 files changed +51 -6
caddyconfig/httpcaddyfile/httptype.go
+48 -3
@@ -372,6 +372,7 @@ func (st *ServerType) serversFromPairings(
372 srv.AutoHTTPS.Skip = append(srv.AutoHTTPS.Skip, autoHTTPSQualifiedHosts...)
373 } else if cpVals, ok := sblock.pile["tls.connection_policy"]; ok {
374 // tls connection policies
375 + var hasCatchAll bool
376 for _, cpVal := range cpVals {
377 cp := cpVal.Value.(*caddytls.ConnectionPolicy)
378
@@ -381,14 +382,31 @@ func (st *ServerType) serversFromPairings(
382 return nil, err
383 }
384
384 - // TODO: are matchers needed if every hostname of the config is matched?
385 + // TODO: are matchers needed if every hostname of the resulting config is matched?
386 if len(hosts) > 0 {
387 cp.MatchersRaw = caddy.ModuleMap{
388 "sni": caddyconfig.JSON(hosts, warnings), // make sure to match all hosts, not just auto-HTTPS-qualified ones
389 }
390 + } else {
391 + hasCatchAll = true
392 }
393 +
394 srv.TLSConnPolicies = append(srv.TLSConnPolicies, cp)
395 }
396 +
397 + // a catch-all is necessary to ensure TLS can be offered to
398 + // all hostnames of the server; even though only one policy
399 + // is needed to enable TLS for the server, that policy might
400 + // apply to only certain TLS handshakes; but when using the
401 + // Caddyfile, user would expect all handshakes to at least
402 + // have a matching connection policy, so here we append a
403 + // catch-all/default policy if there isn't one already (it's
404 + // important that it goes at the end) - see issue #3004:
405 + // https://github.com/caddyserver/caddy/issues/3004
406 + if !hasCatchAll {
407 + srv.TLSConnPolicies = append(srv.TLSConnPolicies, new(caddytls.ConnectionPolicy))
408 + }
409 +
410 // TODO: consolidate equal conn policies
411 }
412
@@ -569,14 +587,41 @@ func consolidateAutomationPolicies(aps []caddytls.AutomationPolicy) []caddytls.A
587 if j == i {
588 continue
589 }
572 - if reflect.DeepEqual(aps[i].ManagementRaw, aps[j].ManagementRaw) {
573 - aps[i].Hosts = append(aps[i].Hosts, aps[j].Hosts...)
590 +
591 + // if they're exactly equal in every way, just keep one of them
592 + if reflect.DeepEqual(aps[i], aps[j]) {
593 aps = append(aps[:j], aps[j+1:]...)
594 i--
595 break
596 }
597 +
598 + // if the policy is the same, we can keep just one, but we have
599 + // to be careful which one we keep; if only one has any hostnames
600 + // defined, then we need to keep the one without any hostnames,
601 + // otherwise the one without any hosts (a catch-all) would be
602 + // eaten up by the one with hosts; and if both have hosts, we
603 + // need to combine their lists
604 + if reflect.DeepEqual(aps[i].ManagementRaw, aps[j].ManagementRaw) &&
605 + aps[i].ManageSync == aps[j].ManageSync {
606 + if len(aps[i].Hosts) == 0 && len(aps[j].Hosts) > 0 {
607 + aps = append(aps[:j], aps[j+1:]...)
608 + } else if len(aps[i].Hosts) > 0 && len(aps[j].Hosts) == 0 {
609 + aps = append(aps[:i], aps[i+1:]...)
610 + } else {
611 + aps[i].Hosts = append(aps[i].Hosts, aps[j].Hosts...)
612 + aps = append(aps[:j], aps[j+1:]...)
613 + }
614 + i--
615 + break
616 + }
617 }
618 }
619 +
620 + // ensure any catch-all policies go last
621 + sort.SliceStable(aps, func(i, j int) bool {
622 + return len(aps[i].Hosts) > len(aps[j].Hosts)
623 + })
624 +
625 return aps
626 }
627
go.mod
+1 -1
@@ -17,7 +17,7 @@ require (
17 github.com/klauspost/cpuid v1.2.2
18 github.com/kylelemons/godebug v1.1.0 // indirect
19 github.com/lucas-clemente/quic-go v0.14.1
20 - github.com/mholt/certmagic v0.9.2
20 + github.com/mholt/certmagic v0.9.3
21 github.com/miekg/dns v1.1.25 // indirect
22 github.com/muhammadmuzzammil1998/jsonc v0.0.0-20190906142622-1265e9b150c6
23 github.com/naoina/go-stringutil v0.1.0 // indirect
go.sum
+2 -2
@@ -225,8 +225,8 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
225 github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
226 github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
227 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
228 -github.com/mholt/certmagic v0.9.2 h1:m+l8jZADOwL2zBVWhaprTnJaRVmRwG4FzR1A8nHwrLw=
229 -github.com/mholt/certmagic v0.9.2/go.mod h1:nu8jbsbtwK4205EDH/ZUMTKsfYpJA1Q7MKXHfgTihNw=
228 +github.com/mholt/certmagic v0.9.3 h1:RmzuNJ5mpFplDbyS41z+gGgE/py24IX6m0nHZ0yNTQU=
229 +github.com/mholt/certmagic v0.9.3/go.mod h1:nu8jbsbtwK4205EDH/ZUMTKsfYpJA1Q7MKXHfgTihNw=
230 github.com/miekg/dns v1.1.15 h1:CSSIDtllwGLMoA6zjdKnaE6Tx6eVUxQ29LUgGetiDCI=
231 github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
232 github.com/miekg/dns v1.1.25 h1:dFwPR6SfLtrSwgDcIq2bcU/gVutB4sNApq2HBdqcakg=