summaryrefslogtreecommitdiff
path: root/caddyconfig
diff options
context:
space:
mode:
Diffstat (limited to 'caddyconfig')
-rw-r--r--caddyconfig/caddyfile/adapter.go5
-rw-r--r--caddyconfig/httpcaddyfile/builtins.go10
-rw-r--r--caddyconfig/httpcaddyfile/httptype.go107
3 files changed, 117 insertions, 5 deletions
diff --git a/caddyconfig/caddyfile/adapter.go b/caddyconfig/caddyfile/adapter.go
index 02a951b..5b4495e 100644
--- a/caddyconfig/caddyfile/adapter.go
+++ b/caddyconfig/caddyfile/adapter.go
@@ -68,6 +68,11 @@ func (a Adapter) Adapt(body []byte, options map[string]interface{}) ([]byte, []c
// into JSON. Caddyfile-unmarshaled values
// will not be used directly; they will be
// encoded as JSON and then used from that.
+// Implementations must be able to support
+// multiple segments (instances of their
+// directive or batch of tokens); typically
+// this means wrapping all token logic in
+// a loop: `for d.Next() { ... }`.
type Unmarshaler interface {
UnmarshalCaddyfile(d *Dispenser) error
}
diff --git a/caddyconfig/httpcaddyfile/builtins.go b/caddyconfig/httpcaddyfile/builtins.go
index 26a421c..1efe5ac 100644
--- a/caddyconfig/httpcaddyfile/builtins.go
+++ b/caddyconfig/httpcaddyfile/builtins.go
@@ -71,6 +71,7 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
cp := new(caddytls.ConnectionPolicy)
var fileLoader caddytls.FileLoader
var folderLoader caddytls.FolderLoader
+ var certSelector caddytls.CustomCertSelectionPolicy
var acmeIssuer *caddytls.ACMEIssuer
var internalIssuer *caddytls.InternalIssuer
var onDemand bool
@@ -135,8 +136,8 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
// remember this for next time we see this cert file
tlsCertTags[certFilename] = tag
}
- certSelector := caddytls.CustomCertSelectionPolicy{Tag: tag}
- cp.CertSelection = caddyconfig.JSONModuleObject(certSelector, "policy", "custom", h.warnings)
+ certSelector.AnyTag = append(certSelector.AnyTag, tag)
+
default:
return nil, h.ArgErr()
}
@@ -297,6 +298,11 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
})
}
+ // custom certificate selection
+ if len(certSelector.AnyTag) > 0 {
+ cp.CertSelection = &certSelector
+ }
+
// connection policy -- always add one, to ensure that TLS
// is enabled, because this directive was used (this is
// needed, for instance, when a site block has a key of
diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go
index f110958..4df5421 100644
--- a/caddyconfig/httpcaddyfile/httptype.go
+++ b/caddyconfig/httpcaddyfile/httptype.go
@@ -527,7 +527,11 @@ func (st *ServerType) serversFromPairings(
}
// tidy things up a bit
- srv.TLSConnPolicies = consolidateConnPolicies(srv.TLSConnPolicies)
+ var err error
+ srv.TLSConnPolicies, err = consolidateConnPolicies(srv.TLSConnPolicies)
+ if err != nil {
+ return nil, fmt.Errorf("consolidating TLS connection policies for server %d: %v", i, err)
+ }
srv.Routes = consolidateRoutes(srv.Routes)
servers[fmt.Sprintf("srv%d", i)] = srv
@@ -538,7 +542,7 @@ func (st *ServerType) serversFromPairings(
// consolidateConnPolicies combines TLS connection policies that are the same,
// for a cleaner overall output.
-func consolidateConnPolicies(cps caddytls.ConnectionPolicies) caddytls.ConnectionPolicies {
+func consolidateConnPolicies(cps caddytls.ConnectionPolicies) (caddytls.ConnectionPolicies, error) {
for i := 0; i < len(cps); i++ {
for j := 0; j < len(cps); j++ {
if j == i {
@@ -551,9 +555,106 @@ func consolidateConnPolicies(cps caddytls.ConnectionPolicies) caddytls.Connectio
i--
break
}
+
+ // if they have the same matcher, try to reconcile each field: either they must
+ // be identical, or we have to be able to combine them safely
+ if reflect.DeepEqual(cps[i].MatchersRaw, cps[j].MatchersRaw) {
+ if len(cps[i].ALPN) > 0 &&
+ len(cps[j].ALPN) > 0 &&
+ !reflect.DeepEqual(cps[i].ALPN, cps[j].ALPN) {
+ return nil, fmt.Errorf("two policies with same match criteria have conflicting ALPN: %v vs. %v",
+ cps[i].ALPN, cps[j].ALPN)
+ }
+ if len(cps[i].CipherSuites) > 0 &&
+ len(cps[j].CipherSuites) > 0 &&
+ !reflect.DeepEqual(cps[i].CipherSuites, cps[j].CipherSuites) {
+ return nil, fmt.Errorf("two policies with same match criteria have conflicting cipher suites: %v vs. %v",
+ cps[i].CipherSuites, cps[j].CipherSuites)
+ }
+ if cps[i].ClientAuthentication == nil &&
+ cps[j].ClientAuthentication != nil &&
+ !reflect.DeepEqual(cps[i].ClientAuthentication, cps[j].ClientAuthentication) {
+ return nil, fmt.Errorf("two policies with same match criteria have conflicting client auth configuration: %+v vs. %+v",
+ cps[i].ClientAuthentication, cps[j].ClientAuthentication)
+ }
+ if len(cps[i].Curves) > 0 &&
+ len(cps[j].Curves) > 0 &&
+ !reflect.DeepEqual(cps[i].Curves, cps[j].Curves) {
+ return nil, fmt.Errorf("two policies with same match criteria have conflicting curves: %v vs. %v",
+ cps[i].Curves, cps[j].Curves)
+ }
+ if cps[i].DefaultSNI != "" &&
+ cps[j].DefaultSNI != "" &&
+ cps[i].DefaultSNI != cps[j].DefaultSNI {
+ return nil, fmt.Errorf("two policies with same match criteria have conflicting default SNI: %s vs. %s",
+ cps[i].DefaultSNI, cps[j].DefaultSNI)
+ }
+ if cps[i].ProtocolMin != "" &&
+ cps[j].ProtocolMin != "" &&
+ cps[i].ProtocolMin != cps[j].ProtocolMin {
+ return nil, fmt.Errorf("two policies with same match criteria have conflicting min protocol: %s vs. %s",
+ cps[i].ProtocolMin, cps[j].ProtocolMin)
+ }
+ if cps[i].ProtocolMax != "" &&
+ cps[j].ProtocolMax != "" &&
+ cps[i].ProtocolMax != cps[j].ProtocolMax {
+ return nil, fmt.Errorf("two policies with same match criteria have conflicting max protocol: %s vs. %s",
+ cps[i].ProtocolMax, cps[j].ProtocolMax)
+ }
+ if cps[i].CertSelection != nil && cps[j].CertSelection != nil {
+ // merging fields other than AnyTag is not implemented
+ if !reflect.DeepEqual(cps[i].CertSelection.SerialNumber, cps[j].CertSelection.SerialNumber) ||
+ !reflect.DeepEqual(cps[i].CertSelection.SubjectOrganization, cps[j].CertSelection.SubjectOrganization) ||
+ cps[i].CertSelection.PublicKeyAlgorithm != cps[j].CertSelection.PublicKeyAlgorithm ||
+ !reflect.DeepEqual(cps[i].CertSelection.AllTags, cps[j].CertSelection.AllTags) {
+ return nil, fmt.Errorf("two policies with same match criteria have conflicting cert selections: %+v vs. %+v",
+ cps[i].CertSelection, cps[j].CertSelection)
+ }
+ }
+
+ // by now we've decided that we can merge the two -- we'll keep i and drop j
+
+ if len(cps[i].ALPN) == 0 && len(cps[j].ALPN) > 0 {
+ cps[i].ALPN = cps[j].ALPN
+ }
+ if len(cps[i].CipherSuites) == 0 && len(cps[j].CipherSuites) > 0 {
+ cps[i].CipherSuites = cps[j].CipherSuites
+ }
+ if cps[i].ClientAuthentication == nil && cps[j].ClientAuthentication != nil {
+ cps[i].ClientAuthentication = cps[j].ClientAuthentication
+ }
+ if len(cps[i].Curves) == 0 && len(cps[j].Curves) > 0 {
+ cps[i].Curves = cps[j].Curves
+ }
+ if cps[i].DefaultSNI == "" && cps[j].DefaultSNI != "" {
+ cps[i].DefaultSNI = cps[j].DefaultSNI
+ }
+ if cps[i].ProtocolMin == "" && cps[j].ProtocolMin != "" {
+ cps[i].ProtocolMin = cps[j].ProtocolMin
+ }
+ if cps[i].ProtocolMax == "" && cps[j].ProtocolMax != "" {
+ cps[i].ProtocolMax = cps[j].ProtocolMax
+ }
+
+ if cps[i].CertSelection == nil && cps[j].CertSelection != nil {
+ // if j is the only one with a policy, move it over to i
+ cps[i].CertSelection = cps[j].CertSelection
+ } else if cps[i].CertSelection != nil && cps[j].CertSelection != nil {
+ // if both have one, then combine AnyTag
+ for _, tag := range cps[j].CertSelection.AnyTag {
+ if !sliceContains(cps[i].CertSelection.AnyTag, tag) {
+ cps[i].CertSelection.AnyTag = append(cps[i].CertSelection.AnyTag, tag)
+ }
+ }
+ }
+
+ cps = append(cps[:j], cps[j+1:]...)
+ i--
+ break
+ }
}
}
- return cps
+ return cps, nil
}
// appendSubrouteToRouteList appends the routes in subroute