aboutsummaryrefslogtreecommitdiffhomepage
path: root/caddyconfig/httpcaddyfile
diff options
context:
space:
mode:
Diffstat (limited to 'caddyconfig/httpcaddyfile')
-rw-r--r--caddyconfig/httpcaddyfile/addresses.go10
-rw-r--r--caddyconfig/httpcaddyfile/builtins.go46
-rw-r--r--caddyconfig/httpcaddyfile/builtins_test.go14
-rw-r--r--caddyconfig/httpcaddyfile/httptype.go77
-rw-r--r--caddyconfig/httpcaddyfile/options.go59
-rw-r--r--caddyconfig/httpcaddyfile/serveroptions.go1
-rw-r--r--caddyconfig/httpcaddyfile/shorthands.go14
-rw-r--r--caddyconfig/httpcaddyfile/tlsapp.go103
8 files changed, 255 insertions, 69 deletions
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
+}