diff options
Diffstat (limited to 'caddyconfig')
-rw-r--r-- | caddyconfig/caddyfile/parse.go | 4 | ||||
-rw-r--r-- | caddyconfig/httpcaddyfile/addresses.go | 10 | ||||
-rw-r--r-- | caddyconfig/httpcaddyfile/builtins.go | 46 | ||||
-rw-r--r-- | caddyconfig/httpcaddyfile/builtins_test.go | 14 | ||||
-rw-r--r-- | caddyconfig/httpcaddyfile/httptype.go | 77 | ||||
-rw-r--r-- | caddyconfig/httpcaddyfile/options.go | 59 | ||||
-rw-r--r-- | caddyconfig/httpcaddyfile/serveroptions.go | 1 | ||||
-rw-r--r-- | caddyconfig/httpcaddyfile/shorthands.go | 14 | ||||
-rw-r--r-- | caddyconfig/httpcaddyfile/tlsapp.go | 103 | ||||
-rw-r--r-- | caddyconfig/httploader.go | 2 |
10 files changed, 258 insertions, 72 deletions
diff --git a/caddyconfig/caddyfile/parse.go b/caddyconfig/caddyfile/parse.go index e19b3b97d..d04a1ac46 100644 --- a/caddyconfig/caddyfile/parse.go +++ b/caddyconfig/caddyfile/parse.go @@ -423,7 +423,7 @@ func (p *parser) doImport(nesting int) error { // make path relative to the file of the _token_ being processed rather // than current working directory (issue #867) and then use glob to get // list of matching filenames - absFile, err := filepath.Abs(p.Dispenser.File()) + absFile, err := caddy.FastAbs(p.Dispenser.File()) if err != nil { return p.Errf("Failed to get absolute path of file: %s: %v", p.Dispenser.File(), err) } @@ -622,7 +622,7 @@ func (p *parser) doSingleImport(importFile string) ([]Token, error) { // Tack the file path onto these tokens so errors show the imported file's name // (we use full, absolute path to avoid bugs: issue #1892) - filename, err := filepath.Abs(importFile) + filename, err := caddy.FastAbs(importFile) if err != nil { return nil, p.Errf("Failed to get absolute path of file: %s: %v", importFile, err) } diff --git a/caddyconfig/httpcaddyfile/addresses.go b/caddyconfig/httpcaddyfile/addresses.go index 1c331eadc..1121776d9 100644 --- a/caddyconfig/httpcaddyfile/addresses.go +++ b/caddyconfig/httpcaddyfile/addresses.go @@ -31,7 +31,7 @@ import ( "github.com/caddyserver/caddy/v2/modules/caddyhttp" ) -// mapAddressToServerBlocks returns a map of listener address to list of server +// mapAddressToProtocolToServerBlocks returns a map of listener address to list of server // blocks that will be served on that address. To do this, each server block is // expanded so that each one is considered individually, although keys of a // server block that share the same address stay grouped together so the config @@ -329,8 +329,12 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad // use a map to prevent duplication listeners := map[string]map[string]struct{}{} for _, lnCfgVal := range lnCfgVals { - for _, lnHost := range lnCfgVal.addresses { - networkAddr, err := caddy.ParseNetworkAddressFromHostPort(lnHost, lnPort) + for _, lnAddr := range lnCfgVal.addresses { + lnNetw, lnHost, _, err := caddy.SplitNetworkAddress(lnAddr) + if err != nil { + return nil, fmt.Errorf("splitting listener address: %v", err) + } + networkAddr, err := caddy.ParseNetworkAddress(caddy.JoinNetworkAddress(lnNetw, lnHost, lnPort)) if err != nil { return nil, fmt.Errorf("parsing network address: %v", err) } diff --git a/caddyconfig/httpcaddyfile/builtins.go b/caddyconfig/httpcaddyfile/builtins.go index 165c66b25..99a4d916a 100644 --- a/caddyconfig/httpcaddyfile/builtins.go +++ b/caddyconfig/httpcaddyfile/builtins.go @@ -24,7 +24,7 @@ import ( "time" "github.com/caddyserver/certmagic" - "github.com/mholt/acmez/v2/acme" + "github.com/mholt/acmez/v3/acme" "go.uber.org/zap/zapcore" "github.com/caddyserver/caddy/v2" @@ -981,6 +981,50 @@ func parseLogHelper(h Helper, globalLogNames map[string]struct{}) ([]ConfigValue } cl.WriterRaw = caddyconfig.JSONModuleObject(wo, "output", moduleName, h.warnings) + case "sampling": + d := h.Dispenser.NewFromNextSegment() + for d.NextArg() { + // consume any tokens on the same line, if any. + } + + sampling := &caddy.LogSampling{} + for nesting := d.Nesting(); d.NextBlock(nesting); { + subdir := d.Val() + switch subdir { + case "interval": + if !d.NextArg() { + return nil, d.ArgErr() + } + interval, err := time.ParseDuration(d.Val() + "ns") + if err != nil { + return nil, d.Errf("failed to parse interval: %v", err) + } + sampling.Interval = interval + case "first": + if !d.NextArg() { + return nil, d.ArgErr() + } + first, err := strconv.Atoi(d.Val()) + if err != nil { + return nil, d.Errf("failed to parse first: %v", err) + } + sampling.First = first + case "thereafter": + if !d.NextArg() { + return nil, d.ArgErr() + } + thereafter, err := strconv.Atoi(d.Val()) + if err != nil { + return nil, d.Errf("failed to parse thereafter: %v", err) + } + sampling.Thereafter = thereafter + default: + return nil, d.Errf("unrecognized subdirective: %s", subdir) + } + } + + cl.Sampling = sampling + case "core": if !h.NextArg() { return nil, h.ArgErr() diff --git a/caddyconfig/httpcaddyfile/builtins_test.go b/caddyconfig/httpcaddyfile/builtins_test.go index cf7463484..c23531f22 100644 --- a/caddyconfig/httpcaddyfile/builtins_test.go +++ b/caddyconfig/httpcaddyfile/builtins_test.go @@ -62,6 +62,20 @@ func TestLogDirectiveSyntax(t *testing.T) { output: `{"logging":{"logs":{"default":{"exclude":["http.log.access.name-override"]},"name-override":{"writer":{"filename":"foo.log","output":"file"},"core":{"module":"mock"},"include":["http.log.access.name-override"]}}},"apps":{"http":{"servers":{"srv0":{"listen":[":8080"],"logs":{"default_logger_name":"name-override"}}}}}}`, expectError: false, }, + { + input: `:8080 { + log { + sampling { + interval 2 + first 3 + thereafter 4 + } + } + } + `, + output: `{"logging":{"logs":{"default":{"exclude":["http.log.access.log0"]},"log0":{"sampling":{"interval":2,"first":3,"thereafter":4},"include":["http.log.access.log0"]}}},"apps":{"http":{"servers":{"srv0":{"listen":[":8080"],"logs":{"default_logger_name":"log0"}}}}}}`, + expectError: false, + }, } { adapter := caddyfile.Adapter{ diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go index 4dacd9058..c169b92af 100644 --- a/caddyconfig/httpcaddyfile/httptype.go +++ b/caddyconfig/httpcaddyfile/httptype.go @@ -15,6 +15,7 @@ package httpcaddyfile import ( + "cmp" "encoding/json" "fmt" "net" @@ -186,12 +187,25 @@ func (st ServerType) Setup( return nil, warnings, err } + // hoist the metrics config from per-server to global + metrics, _ := options["metrics"].(*caddyhttp.Metrics) + for _, s := range servers { + if s.Metrics != nil { + metrics = cmp.Or[*caddyhttp.Metrics](metrics, &caddyhttp.Metrics{}) + metrics = &caddyhttp.Metrics{ + PerHost: metrics.PerHost || s.Metrics.PerHost, + } + s.Metrics = nil // we don't need it anymore + } + } + // now that each server is configured, make the HTTP app httpApp := caddyhttp.App{ HTTPPort: tryInt(options["http_port"], &warnings), HTTPSPort: tryInt(options["https_port"], &warnings), GracePeriod: tryDuration(options["grace_period"], &warnings), ShutdownDelay: tryDuration(options["shutdown_delay"], &warnings), + Metrics: metrics, Servers: servers, } @@ -692,6 +706,16 @@ func (st *ServerType) serversFromPairings( return specificity(iLongestHost) > specificity(jLongestHost) }) + // collect all hosts that have a wildcard in them + wildcardHosts := []string{} + for _, sblock := range p.serverBlocks { + for _, addr := range sblock.parsedKeys { + if strings.HasPrefix(addr.Host, "*.") { + wildcardHosts = append(wildcardHosts, addr.Host[2:]) + } + } + } + var hasCatchAllTLSConnPolicy, addressQualifiesForTLS bool autoHTTPSWillAddConnPolicy := srv.AutoHTTPS == nil || !srv.AutoHTTPS.Disabled @@ -777,13 +801,6 @@ func (st *ServerType) serversFromPairings( } } - wildcardHosts := []string{} - for _, addr := range sblock.parsedKeys { - if strings.HasPrefix(addr.Host, "*.") { - wildcardHosts = append(wildcardHosts, addr.Host[2:]) - } - } - for _, addr := range sblock.parsedKeys { // if server only uses HTTP port, auto-HTTPS will not apply if listenersUseAnyPortOtherThan(srv.Listen, httpPort) { @@ -799,18 +816,6 @@ func (st *ServerType) serversFromPairings( } } - // If prefer wildcard is enabled, then we add hosts that are - // already covered by the wildcard to the skip list - if srv.AutoHTTPS != nil && srv.AutoHTTPS.PreferWildcard && addr.Scheme == "https" { - baseDomain := addr.Host - if idx := strings.Index(baseDomain, "."); idx != -1 { - baseDomain = baseDomain[idx+1:] - } - if !strings.HasPrefix(addr.Host, "*.") && slices.Contains(wildcardHosts, baseDomain) { - srv.AutoHTTPS.Skip = append(srv.AutoHTTPS.Skip, addr.Host) - } - } - // If TLS is specified as directive, it will also result in 1 or more connection policy being created // Thus, catch-all address with non-standard port, e.g. :8443, can have TLS enabled without // specifying prefix "https://" @@ -827,6 +832,19 @@ func (st *ServerType) serversFromPairings( (addr.Scheme != "http" && addr.Port != httpPort && hasTLSEnabled) { addressQualifiesForTLS = true } + + // If prefer wildcard is enabled, then we add hosts that are + // already covered by the wildcard to the skip list + if addressQualifiesForTLS && srv.AutoHTTPS != nil && srv.AutoHTTPS.PreferWildcard { + baseDomain := addr.Host + if idx := strings.Index(baseDomain, "."); idx != -1 { + baseDomain = baseDomain[idx+1:] + } + if !strings.HasPrefix(addr.Host, "*.") && slices.Contains(wildcardHosts, baseDomain) { + srv.AutoHTTPS.SkipCerts = append(srv.AutoHTTPS.SkipCerts, addr.Host) + } + } + // predict whether auto-HTTPS will add the conn policy for us; if so, we // may not need to add one for this server autoHTTPSWillAddConnPolicy = autoHTTPSWillAddConnPolicy && @@ -1448,9 +1466,9 @@ func (st *ServerType) compileEncodedMatcherSets(sblock serverBlock) ([]caddy.Mod // iterate each pairing of host and path matchers and // put them into a map for JSON encoding - var matcherSets []map[string]caddyhttp.RequestMatcher + var matcherSets []map[string]caddyhttp.RequestMatcherWithError for _, mp := range matcherPairs { - matcherSet := make(map[string]caddyhttp.RequestMatcher) + matcherSet := make(map[string]caddyhttp.RequestMatcherWithError) if len(mp.hostm) > 0 { matcherSet["host"] = mp.hostm } @@ -1509,12 +1527,17 @@ func parseMatcherDefinitions(d *caddyfile.Dispenser, matchers map[string]caddy.M if err != nil { return err } - rm, ok := unm.(caddyhttp.RequestMatcher) - if !ok { - return fmt.Errorf("matcher module '%s' is not a request matcher", matcherName) + + if rm, ok := unm.(caddyhttp.RequestMatcherWithError); ok { + matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil) + return nil } - matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil) - return nil + // nolint:staticcheck + if rm, ok := unm.(caddyhttp.RequestMatcher); ok { + matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil) + return nil + } + return fmt.Errorf("matcher module '%s' is not a request matcher", matcherName) } // if the next token is quoted, we can assume it's not a matcher name @@ -1558,7 +1581,7 @@ func parseMatcherDefinitions(d *caddyfile.Dispenser, matchers map[string]caddy.M return nil } -func encodeMatcherSet(matchers map[string]caddyhttp.RequestMatcher) (caddy.ModuleMap, error) { +func encodeMatcherSet(matchers map[string]caddyhttp.RequestMatcherWithError) (caddy.ModuleMap, error) { msEncoded := make(caddy.ModuleMap) for matcherName, val := range matchers { jsonBytes, err := json.Marshal(val) diff --git a/caddyconfig/httpcaddyfile/options.go b/caddyconfig/httpcaddyfile/options.go index 9bae760c0..d4a424624 100644 --- a/caddyconfig/httpcaddyfile/options.go +++ b/caddyconfig/httpcaddyfile/options.go @@ -19,11 +19,12 @@ import ( "strconv" "github.com/caddyserver/certmagic" - "github.com/mholt/acmez/v2/acme" + "github.com/mholt/acmez/v3/acme" "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" + "github.com/caddyserver/caddy/v2/modules/caddyhttp" "github.com/caddyserver/caddy/v2/modules/caddytls" ) @@ -38,7 +39,8 @@ func init() { RegisterGlobalOption("fallback_sni", parseOptSingleString) RegisterGlobalOption("order", parseOptOrder) RegisterGlobalOption("storage", parseOptStorage) - RegisterGlobalOption("storage_clean_interval", parseOptDuration) + RegisterGlobalOption("storage_check", parseStorageCheck) + RegisterGlobalOption("storage_clean_interval", parseStorageCleanInterval) RegisterGlobalOption("renew_interval", parseOptDuration) RegisterGlobalOption("ocsp_interval", parseOptDuration) RegisterGlobalOption("acme_ca", parseOptSingleString) @@ -53,6 +55,7 @@ func init() { RegisterGlobalOption("local_certs", parseOptTrue) RegisterGlobalOption("key_type", parseOptSingleString) RegisterGlobalOption("auto_https", parseOptAutoHTTPS) + RegisterGlobalOption("metrics", parseMetricsOptions) RegisterGlobalOption("servers", parseServerOptions) RegisterGlobalOption("ocsp_stapling", parseOCSPStaplingOptions) RegisterGlobalOption("cert_lifetime", parseOptDuration) @@ -187,6 +190,40 @@ func parseOptStorage(d *caddyfile.Dispenser, _ any) (any, error) { return storage, nil } +func parseStorageCheck(d *caddyfile.Dispenser, _ any) (any, error) { + d.Next() // consume option name + if !d.Next() { + return "", d.ArgErr() + } + val := d.Val() + if d.Next() { + return "", d.ArgErr() + } + if val != "off" { + return "", d.Errf("storage_check must be 'off'") + } + return val, nil +} + +func parseStorageCleanInterval(d *caddyfile.Dispenser, _ any) (any, error) { + d.Next() // consume option name + if !d.Next() { + return "", d.ArgErr() + } + val := d.Val() + if d.Next() { + return "", d.ArgErr() + } + if val == "off" { + return false, nil + } + dur, err := caddy.ParseDuration(d.Val()) + if err != nil { + return nil, d.Errf("failed to parse storage_clean_interval, must be a duration or 'off' %w", err) + } + return caddy.Duration(dur), nil +} + func parseOptDuration(d *caddyfile.Dispenser, _ any) (any, error) { if !d.Next() { // consume option name return nil, d.ArgErr() @@ -446,6 +483,24 @@ func parseOptAutoHTTPS(d *caddyfile.Dispenser, _ any) (any, error) { return val, nil } +func unmarshalCaddyfileMetricsOptions(d *caddyfile.Dispenser) (any, error) { + d.Next() // consume option name + metrics := new(caddyhttp.Metrics) + for d.NextBlock(0) { + switch d.Val() { + case "per_host": + metrics.PerHost = true + default: + return nil, d.Errf("unrecognized servers option '%s'", d.Val()) + } + } + return metrics, nil +} + +func parseMetricsOptions(d *caddyfile.Dispenser, _ any) (any, error) { + return unmarshalCaddyfileMetricsOptions(d) +} + func parseServerOptions(d *caddyfile.Dispenser, _ any) (any, error) { return unmarshalCaddyfileServerOptions(d) } diff --git a/caddyconfig/httpcaddyfile/serveroptions.go b/caddyconfig/httpcaddyfile/serveroptions.go index b05af47f5..40a8af209 100644 --- a/caddyconfig/httpcaddyfile/serveroptions.go +++ b/caddyconfig/httpcaddyfile/serveroptions.go @@ -240,6 +240,7 @@ func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) { } case "metrics": + caddy.Log().Warn("The nested 'metrics' option inside `servers` is deprecated and will be removed in the next major version. Use the global 'metrics' option instead.") serverOpts.Metrics = new(caddyhttp.Metrics) for nesting := d.Nesting(); d.NextBlock(nesting); { switch d.Val() { diff --git a/caddyconfig/httpcaddyfile/shorthands.go b/caddyconfig/httpcaddyfile/shorthands.go index 5d9ef31eb..ca6e4f92c 100644 --- a/caddyconfig/httpcaddyfile/shorthands.go +++ b/caddyconfig/httpcaddyfile/shorthands.go @@ -52,19 +52,27 @@ func NewShorthandReplacer() ShorthandReplacer { // be used in the Caddyfile, and the right is the replacement. func placeholderShorthands() []string { return []string{ - "{dir}", "{http.request.uri.path.dir}", - "{file}", "{http.request.uri.path.file}", "{host}", "{http.request.host}", "{hostport}", "{http.request.hostport}", "{port}", "{http.request.port}", + "{orig_method}", "{http.request.orig_method}", + "{orig_uri}", "{http.request.orig_uri}", + "{orig_path}", "{http.request.orig_uri.path}", + "{orig_dir}", "{http.request.orig_uri.path.dir}", + "{orig_file}", "{http.request.orig_uri.path.file}", + "{orig_query}", "{http.request.orig_uri.query}", + "{orig_?query}", "{http.request.orig_uri.prefixed_query}", "{method}", "{http.request.method}", + "{uri}", "{http.request.uri}", "{path}", "{http.request.uri.path}", + "{dir}", "{http.request.uri.path.dir}", + "{file}", "{http.request.uri.path.file}", "{query}", "{http.request.uri.query}", + "{?query}", "{http.request.uri.prefixed_query}", "{remote}", "{http.request.remote}", "{remote_host}", "{http.request.remote.host}", "{remote_port}", "{http.request.remote.port}", "{scheme}", "{http.request.scheme}", - "{uri}", "{http.request.uri}", "{uuid}", "{http.request.uuid}", "{tls_cipher}", "{http.request.tls.cipher_suite}", "{tls_version}", "{http.request.tls.version}", diff --git a/caddyconfig/httpcaddyfile/tlsapp.go b/caddyconfig/httpcaddyfile/tlsapp.go index ed708524d..397323f71 100644 --- a/caddyconfig/httpcaddyfile/tlsapp.go +++ b/caddyconfig/httpcaddyfile/tlsapp.go @@ -25,7 +25,7 @@ import ( "strings" "github.com/caddyserver/certmagic" - "github.com/mholt/acmez/v2/acme" + "github.com/mholt/acmez/v3/acme" "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig" @@ -92,6 +92,25 @@ func (st ServerType) buildTLSApp( tlsApp.Automation.Policies = append(tlsApp.Automation.Policies, catchAllAP) } + // collect all hosts that have a wildcard in them, and arent HTTP + wildcardHosts := []string{} + for _, p := range pairings { + var addresses []string + for _, addressWithProtocols := range p.addressesWithProtocols { + addresses = append(addresses, addressWithProtocols.address) + } + if !listenersUseAnyPortOtherThan(addresses, httpPort) { + continue + } + for _, sblock := range p.serverBlocks { + for _, addr := range sblock.parsedKeys { + if strings.HasPrefix(addr.Host, "*.") { + wildcardHosts = append(wildcardHosts, addr.Host[2:]) + } + } + } + } + for _, p := range pairings { // avoid setting up TLS automation policies for a server that is HTTP-only var addresses []string @@ -115,6 +134,12 @@ func (st ServerType) buildTLSApp( return nil, warnings, err } + // make a plain copy so we can compare whether we made any changes + apCopy, err := newBaseAutomationPolicy(options, warnings, true) + if err != nil { + return nil, warnings, err + } + sblockHosts := sblock.hostsFromKeys(false) if len(sblockHosts) == 0 && catchAllAP != nil { ap = catchAllAP @@ -217,9 +242,21 @@ func (st ServerType) buildTLSApp( catchAllAP = ap } + hostsNotHTTP := sblock.hostsFromKeysNotHTTP(httpPort) + sort.Strings(hostsNotHTTP) // solely for deterministic test results + + // if the we prefer wildcards and the AP is unchanged, + // then we can skip this AP because it should be covered + // by an AP with a wildcard + if slices.Contains(autoHTTPS, "prefer_wildcard") { + if hostsCoveredByWildcard(hostsNotHTTP, wildcardHosts) && + reflect.DeepEqual(ap, apCopy) { + continue + } + } + // associate our new automation policy with this server block's hosts - ap.SubjectsRaw = sblock.hostsFromKeysNotHTTP(httpPort) - sort.Strings(ap.SubjectsRaw) // solely for deterministic test results + ap.SubjectsRaw = hostsNotHTTP // if a combination of public and internal names were given // for this same server block and no issuer was specified, we @@ -258,6 +295,7 @@ func (st ServerType) buildTLSApp( ap2.IssuersRaw = []json.RawMessage{caddyconfig.JSONModuleObject(caddytls.InternalIssuer{}, "module", "internal", &warnings)} } } + if tlsApp.Automation == nil { tlsApp.Automation = new(caddytls.AutomationConfig) } @@ -311,6 +349,16 @@ func (st ServerType) buildTLSApp( tlsApp.Automation.OnDemand = onDemand } + // if the storage clean interval is a boolean, then it's "off" to disable cleaning + if sc, ok := options["storage_check"].(string); ok && sc == "off" { + tlsApp.DisableStorageCheck = true + } + + // if the storage clean interval is a boolean, then it's "off" to disable cleaning + if sci, ok := options["storage_clean_interval"].(bool); ok && !sci { + tlsApp.DisableStorageClean = true + } + // set the storage clean interval if configured if storageCleanInterval, ok := options["storage_clean_interval"].(caddy.Duration); ok { if tlsApp.Automation == nil { @@ -418,10 +466,7 @@ func (st ServerType) buildTLSApp( } // consolidate automation policies that are the exact same - tlsApp.Automation.Policies = consolidateAutomationPolicies( - tlsApp.Automation.Policies, - slices.Contains(autoHTTPS, "prefer_wildcard"), - ) + tlsApp.Automation.Policies = consolidateAutomationPolicies(tlsApp.Automation.Policies) // ensure automation policies don't overlap subjects (this should be // an error at provision-time as well, but catch it in the adapt phase @@ -567,7 +612,7 @@ func newBaseAutomationPolicy( // consolidateAutomationPolicies combines automation policies that are the same, // for a cleaner overall output. -func consolidateAutomationPolicies(aps []*caddytls.AutomationPolicy, preferWildcard bool) []*caddytls.AutomationPolicy { +func consolidateAutomationPolicies(aps []*caddytls.AutomationPolicy) []*caddytls.AutomationPolicy { // sort from most specific to least specific; we depend on this ordering sort.SliceStable(aps, func(i, j int) bool { if automationPolicyIsSubset(aps[i], aps[j]) { @@ -652,31 +697,6 @@ outer: j-- } } - - if preferWildcard { - // remove subjects from i if they're covered by a wildcard in j - iSubjs := aps[i].SubjectsRaw - for iSubj := 0; iSubj < len(iSubjs); iSubj++ { - for jSubj := range aps[j].SubjectsRaw { - if !strings.HasPrefix(aps[j].SubjectsRaw[jSubj], "*.") { - continue - } - if certmagic.MatchWildcard(aps[i].SubjectsRaw[iSubj], aps[j].SubjectsRaw[jSubj]) { - iSubjs = slices.Delete(iSubjs, iSubj, iSubj+1) - iSubj-- - break - } - } - } - aps[i].SubjectsRaw = iSubjs - - // remove i if it has no subjects left - if len(aps[i].SubjectsRaw) == 0 { - aps = slices.Delete(aps, i, i+1) - i-- - continue outer - } - } } } @@ -748,3 +768,20 @@ func automationPolicyHasAllPublicNames(ap *caddytls.AutomationPolicy) bool { func isTailscaleDomain(name string) bool { return strings.HasSuffix(strings.ToLower(name), ".ts.net") } + +func hostsCoveredByWildcard(hosts []string, wildcards []string) bool { + if len(hosts) == 0 || len(wildcards) == 0 { + return false + } + for _, host := range hosts { + for _, wildcard := range wildcards { + if strings.HasPrefix(host, "*.") { + continue + } + if certmagic.MatchWildcard(host, "*."+wildcard) { + return true + } + } + } + return false +} diff --git a/caddyconfig/httploader.go b/caddyconfig/httploader.go index 55fadf65b..a25041a34 100644 --- a/caddyconfig/httploader.go +++ b/caddyconfig/httploader.go @@ -35,7 +35,7 @@ func init() { // If the response is not a JSON config, a config adapter must be specified // either in the loader config (`adapter`), or in the Content-Type HTTP header // returned in the HTTP response from the server. The Content-Type header is -// read just like the admin API's `/load` endpoint. Uf you don't have control +// read just like the admin API's `/load` endpoint. If you don't have control // over the HTTP server (but can still trust its response), you can override // the Content-Type header by setting the `adapter` property in this config. type HTTPLoader struct { |