mirror of
https://github.com/caddyserver/caddy.git
synced 2025-05-24 02:02:26 -04:00
Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a76d005a94 | ||
|
8524386737 | ||
|
94147caf31 | ||
|
716d72e475 | ||
|
44d078b670 | ||
|
051e73aefc | ||
|
9f7148392a | ||
|
320c57291d | ||
|
aa3d20be3e | ||
|
54d03ced48 | ||
|
89ed5f44de | ||
|
105eee671c | ||
|
737936c06b | ||
|
a6d488a15b |
14
admin.go
14
admin.go
@ -424,6 +424,13 @@ func replaceLocalAdminServer(cfg *Config, ctx Context) error {
|
||||
|
||||
handler := cfg.Admin.newAdminHandler(addr, false, ctx)
|
||||
|
||||
// run the provisioners for loaded modules to make sure local
|
||||
// state is properly re-initialized in the new admin server
|
||||
err = cfg.Admin.provisionAdminRouters(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ln, err := addr.Listen(context.TODO(), 0, net.ListenConfig{})
|
||||
if err != nil {
|
||||
return err
|
||||
@ -545,6 +552,13 @@ func replaceRemoteAdminServer(ctx Context, cfg *Config) error {
|
||||
// because we are using TLS authentication instead
|
||||
handler := cfg.Admin.newAdminHandler(addr, true, ctx)
|
||||
|
||||
// run the provisioners for loaded modules to make sure local
|
||||
// state is properly re-initialized in the new admin server
|
||||
err = cfg.Admin.provisionAdminRouters(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create client certificate pool for TLS mutual auth, and extract public keys
|
||||
// so that we can enforce access controls at the application layer
|
||||
clientCertPool := x509.NewCertPool()
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"maps"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
@ -335,9 +336,7 @@ func TestAdminHandlerBuiltinRouteErrors(t *testing.T) {
|
||||
|
||||
func testGetMetricValue(labels map[string]string) float64 {
|
||||
promLabels := prometheus.Labels{}
|
||||
for k, v := range labels {
|
||||
promLabels[k] = v
|
||||
}
|
||||
maps.Copy(promLabels, labels)
|
||||
|
||||
metric, err := adminMetrics.requestErrors.GetMetricWith(promLabels)
|
||||
if err != nil {
|
||||
@ -377,9 +376,7 @@ func (m *mockModule) CaddyModule() ModuleInfo {
|
||||
|
||||
func TestNewAdminHandlerRouterRegistration(t *testing.T) {
|
||||
originalModules := make(map[string]ModuleInfo)
|
||||
for k, v := range modules {
|
||||
originalModules[k] = v
|
||||
}
|
||||
maps.Copy(originalModules, modules)
|
||||
defer func() {
|
||||
modules = originalModules
|
||||
}()
|
||||
@ -479,9 +476,7 @@ func TestAdminRouterProvisioning(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
originalModules := make(map[string]ModuleInfo)
|
||||
for k, v := range modules {
|
||||
originalModules[k] = v
|
||||
}
|
||||
maps.Copy(originalModules, modules)
|
||||
defer func() {
|
||||
modules = originalModules
|
||||
}()
|
||||
@ -774,9 +769,7 @@ func (m *mockIssuerModule) CaddyModule() ModuleInfo {
|
||||
|
||||
func TestManageIdentity(t *testing.T) {
|
||||
originalModules := make(map[string]ModuleInfo)
|
||||
for k, v := range modules {
|
||||
originalModules[k] = v
|
||||
}
|
||||
maps.Copy(originalModules, modules)
|
||||
defer func() {
|
||||
modules = originalModules
|
||||
}()
|
||||
|
16
caddy.go
16
caddy.go
@ -505,14 +505,6 @@ func provisionContext(newCfg *Config, replaceAdminServer bool) (Context, error)
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
// start the admin endpoint (and stop any prior one)
|
||||
if replaceAdminServer {
|
||||
err = replaceLocalAdminServer(newCfg, ctx)
|
||||
if err != nil {
|
||||
return ctx, fmt.Errorf("starting caddy administration endpoint: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// create the new filesystem map
|
||||
newCfg.fileSystems = &filesystems.FileSystemMap{}
|
||||
|
||||
@ -544,6 +536,14 @@ func provisionContext(newCfg *Config, replaceAdminServer bool) (Context, error)
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
// start the admin endpoint (and stop any prior one)
|
||||
if replaceAdminServer {
|
||||
err = replaceLocalAdminServer(newCfg, ctx)
|
||||
if err != nil {
|
||||
return ctx, fmt.Errorf("starting caddy administration endpoint: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Load and Provision each app and their submodules
|
||||
err = func() error {
|
||||
for appName := range newCfg.AppsRaw {
|
||||
|
@ -16,6 +16,7 @@ package httpcaddyfile
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"maps"
|
||||
"net"
|
||||
"slices"
|
||||
"sort"
|
||||
@ -365,9 +366,7 @@ func parseSegmentAsConfig(h Helper) ([]ConfigValue, error) {
|
||||
// copy existing matcher definitions so we can augment
|
||||
// new ones that are defined only in this scope
|
||||
matcherDefs := make(map[string]caddy.ModuleMap, len(h.matcherDefs))
|
||||
for key, val := range h.matcherDefs {
|
||||
matcherDefs[key] = val
|
||||
}
|
||||
maps.Copy(matcherDefs, h.matcherDefs)
|
||||
|
||||
// find and extract any embedded matcher definitions in this scope
|
||||
for i := 0; i < len(segments); i++ {
|
||||
@ -483,12 +482,29 @@ func sortRoutes(routes []ConfigValue) {
|
||||
// we can only confidently compare path lengths if both
|
||||
// directives have a single path to match (issue #5037)
|
||||
if iPathLen > 0 && jPathLen > 0 {
|
||||
// trim the trailing wildcard if there is one
|
||||
iPathTrimmed := strings.TrimSuffix(iPM[0], "*")
|
||||
jPathTrimmed := strings.TrimSuffix(jPM[0], "*")
|
||||
|
||||
// if both paths are the same except for a trailing wildcard,
|
||||
// sort by the shorter path first (which is more specific)
|
||||
if strings.TrimSuffix(iPM[0], "*") == strings.TrimSuffix(jPM[0], "*") {
|
||||
if iPathTrimmed == jPathTrimmed {
|
||||
return iPathLen < jPathLen
|
||||
}
|
||||
|
||||
// we use the trimmed length to compare the paths
|
||||
// https://github.com/caddyserver/caddy/issues/7012#issuecomment-2870142195
|
||||
// credit to https://github.com/Hellio404
|
||||
// for sorts with many items, mixing matchers w/ and w/o wildcards will confuse the sort and result in incorrect orders
|
||||
iPathLen = len(iPathTrimmed)
|
||||
jPathLen = len(jPathTrimmed)
|
||||
|
||||
// if both paths have the same length, sort lexically
|
||||
// https://github.com/caddyserver/caddy/pull/7015#issuecomment-2871993588
|
||||
if iPathLen == jPathLen {
|
||||
return iPathTrimmed < jPathTrimmed
|
||||
}
|
||||
|
||||
// sort most-specific (longest) path first
|
||||
return iPathLen > jPathLen
|
||||
}
|
||||
|
@ -0,0 +1,72 @@
|
||||
{
|
||||
pki {
|
||||
ca custom-ca {
|
||||
name "Custom CA"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
acme.example.com {
|
||||
acme_server {
|
||||
ca custom-ca
|
||||
allow {
|
||||
domains host-1.internal.example.com host-2.internal.example.com
|
||||
}
|
||||
}
|
||||
}
|
||||
----------
|
||||
{
|
||||
"apps": {
|
||||
"http": {
|
||||
"servers": {
|
||||
"srv0": {
|
||||
"listen": [
|
||||
":443"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": [
|
||||
{
|
||||
"host": [
|
||||
"acme.example.com"
|
||||
]
|
||||
}
|
||||
],
|
||||
"handle": [
|
||||
{
|
||||
"handler": "subroute",
|
||||
"routes": [
|
||||
{
|
||||
"handle": [
|
||||
{
|
||||
"ca": "custom-ca",
|
||||
"handler": "acme_server",
|
||||
"policy": {
|
||||
"allow": {
|
||||
"domains": [
|
||||
"host-1.internal.example.com",
|
||||
"host-2.internal.example.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"terminal": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"pki": {
|
||||
"certificate_authorities": {
|
||||
"custom-ca": {
|
||||
"name": "Custom CA"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
{
|
||||
pki {
|
||||
ca custom-ca {
|
||||
name "Custom CA"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
acme.example.com {
|
||||
acme_server {
|
||||
ca custom-ca
|
||||
allow {
|
||||
domains host-1.internal.example.com host-2.internal.example.com
|
||||
}
|
||||
deny {
|
||||
domains dc.internal.example.com
|
||||
}
|
||||
}
|
||||
}
|
||||
----------
|
||||
{
|
||||
"apps": {
|
||||
"http": {
|
||||
"servers": {
|
||||
"srv0": {
|
||||
"listen": [
|
||||
":443"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": [
|
||||
{
|
||||
"host": [
|
||||
"acme.example.com"
|
||||
]
|
||||
}
|
||||
],
|
||||
"handle": [
|
||||
{
|
||||
"handler": "subroute",
|
||||
"routes": [
|
||||
{
|
||||
"handle": [
|
||||
{
|
||||
"ca": "custom-ca",
|
||||
"handler": "acme_server",
|
||||
"policy": {
|
||||
"allow": {
|
||||
"domains": [
|
||||
"host-1.internal.example.com",
|
||||
"host-2.internal.example.com"
|
||||
]
|
||||
},
|
||||
"deny": {
|
||||
"domains": [
|
||||
"dc.internal.example.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"terminal": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"pki": {
|
||||
"certificate_authorities": {
|
||||
"custom-ca": {
|
||||
"name": "Custom CA"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
{
|
||||
pki {
|
||||
ca custom-ca {
|
||||
name "Custom CA"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
acme.example.com {
|
||||
acme_server {
|
||||
ca custom-ca
|
||||
deny {
|
||||
domains dc.internal.example.com
|
||||
}
|
||||
}
|
||||
}
|
||||
----------
|
||||
{
|
||||
"apps": {
|
||||
"http": {
|
||||
"servers": {
|
||||
"srv0": {
|
||||
"listen": [
|
||||
":443"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": [
|
||||
{
|
||||
"host": [
|
||||
"acme.example.com"
|
||||
]
|
||||
}
|
||||
],
|
||||
"handle": [
|
||||
{
|
||||
"handler": "subroute",
|
||||
"routes": [
|
||||
{
|
||||
"handle": [
|
||||
{
|
||||
"ca": "custom-ca",
|
||||
"handler": "acme_server",
|
||||
"policy": {
|
||||
"deny": {
|
||||
"domains": [
|
||||
"dc.internal.example.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"terminal": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"pki": {
|
||||
"certificate_authorities": {
|
||||
"custom-ca": {
|
||||
"name": "Custom CA"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"maps"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -703,9 +704,7 @@ func AdminAPIRequest(adminAddr, method, uri string, headers http.Header, body io
|
||||
if body != nil {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
for k, v := range headers {
|
||||
req.Header[k] = v
|
||||
}
|
||||
maps.Copy(req.Header, headers)
|
||||
|
||||
// make an HTTP client that dials our network type, since admin
|
||||
// endpoints aren't always TCP, which is what the default transport
|
||||
|
@ -577,11 +577,11 @@ func (ctx Context) Slogger() *slog.Logger {
|
||||
if err != nil {
|
||||
panic("config missing, unable to create dev logger: " + err.Error())
|
||||
}
|
||||
return slog.New(zapslog.NewHandler(l.Core(), nil))
|
||||
return slog.New(zapslog.NewHandler(l.Core()))
|
||||
}
|
||||
mod := ctx.Module()
|
||||
if mod == nil {
|
||||
return slog.New(zapslog.NewHandler(Log().Core(), nil))
|
||||
return slog.New(zapslog.NewHandler(Log().Core()))
|
||||
}
|
||||
return slog.New(zapslog.NewHandler(ctx.cfg.Logging.Logger(mod).Core(),
|
||||
zapslog.WithName(string(mod.CaddyModule().ID)),
|
||||
|
2
go.mod
2
go.mod
@ -19,7 +19,7 @@ require (
|
||||
github.com/klauspost/cpuid/v2 v2.2.10
|
||||
github.com/mholt/acmez/v3 v3.1.2
|
||||
github.com/prometheus/client_golang v1.19.1
|
||||
github.com/quic-go/quic-go v0.50.1
|
||||
github.com/quic-go/quic-go v0.51.0
|
||||
github.com/smallstep/certificates v0.26.1
|
||||
github.com/smallstep/nosql v0.6.1
|
||||
github.com/smallstep/truststore v0.13.0
|
||||
|
4
go.sum
4
go.sum
@ -397,8 +397,8 @@ github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.50.1 h1:unsgjFIUqW8a2oopkY7YNONpV1gYND6Nt9hnt1PN94Q=
|
||||
github.com/quic-go/quic-go v0.50.1/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E=
|
||||
github.com/quic-go/quic-go v0.51.0 h1:K8exxe9zXxeRKxaXxi/GpUqYiTrtdiWP8bo1KFya6Wc=
|
||||
github.com/quic-go/quic-go v0.51.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
|
@ -162,7 +162,9 @@ func (logging *Logging) setupNewDefault(ctx Context) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("setting up default log: %v", err)
|
||||
}
|
||||
newDefault.logger = zap.New(newDefault.CustomLog.core, options...)
|
||||
|
||||
filteringCore := &filteringCore{newDefault.CustomLog.core, newDefault.CustomLog}
|
||||
newDefault.logger = zap.New(filteringCore, options...)
|
||||
|
||||
// redirect the default caddy logs
|
||||
defaultLoggerMu.Lock()
|
||||
|
106
logging_test.go
Normal file
106
logging_test.go
Normal file
@ -0,0 +1,106 @@
|
||||
// Copyright 2015 Matthew Holt and The Caddy Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package caddy
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCustomLog_loggerAllowed(t *testing.T) {
|
||||
type fields struct {
|
||||
BaseLog BaseLog
|
||||
Include []string
|
||||
Exclude []string
|
||||
}
|
||||
type args struct {
|
||||
name string
|
||||
isModule bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "include",
|
||||
fields: fields{
|
||||
Include: []string{"foo"},
|
||||
},
|
||||
args: args{
|
||||
name: "foo",
|
||||
isModule: true,
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "exclude",
|
||||
fields: fields{
|
||||
Exclude: []string{"foo"},
|
||||
},
|
||||
args: args{
|
||||
name: "foo",
|
||||
isModule: true,
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "include and exclude",
|
||||
fields: fields{
|
||||
Include: []string{"foo"},
|
||||
Exclude: []string{"foo"},
|
||||
},
|
||||
args: args{
|
||||
name: "foo",
|
||||
isModule: true,
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "include and exclude (longer namespace)",
|
||||
fields: fields{
|
||||
Include: []string{"foo.bar"},
|
||||
Exclude: []string{"foo"},
|
||||
},
|
||||
args: args{
|
||||
name: "foo.bar",
|
||||
isModule: true,
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "excluded module is not printed",
|
||||
fields: fields{
|
||||
Include: []string{"admin.api.load"},
|
||||
Exclude: []string{"admin.api"},
|
||||
},
|
||||
args: args{
|
||||
name: "admin.api",
|
||||
isModule: false,
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cl := &CustomLog{
|
||||
BaseLog: tt.fields.BaseLog,
|
||||
Include: tt.fields.Include,
|
||||
Exclude: tt.fields.Exclude,
|
||||
}
|
||||
if got := cl.loggerAllowed(tt.args.name, tt.args.isModule); got != tt.want {
|
||||
t.Errorf("CustomLog.loggerAllowed() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@
|
||||
<path d="M9 7l4 0"/>
|
||||
<path d="M9 11l4 0"/>
|
||||
</svg>
|
||||
{{- else if .HasExt ".jpg" ".jpeg" ".png" ".gif" ".webp" ".tiff" ".bmp" ".heif" ".heic" ".svg"}}
|
||||
{{- else if .HasExt ".jpg" ".jpeg" ".png" ".gif" ".webp" ".tiff" ".bmp" ".heif" ".heic" ".svg" ".avif"}}
|
||||
{{- if eq .Tpl.Layout "grid"}}
|
||||
<img loading="lazy" src="{{.Name | pathEscape}}">
|
||||
{{- else}}
|
||||
|
@ -300,8 +300,10 @@ func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next c
|
||||
info, err := fs.Stat(fileSystem, filename)
|
||||
if err != nil {
|
||||
err = fsrv.mapDirOpenError(fileSystem, err, filename)
|
||||
if errors.Is(err, fs.ErrNotExist) || errors.Is(err, fs.ErrInvalid) {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return fsrv.notFound(w, r, next)
|
||||
} else if errors.Is(err, fs.ErrInvalid) {
|
||||
return caddyhttp.Error(http.StatusBadRequest, err)
|
||||
} else if errors.Is(err, fs.ErrPermission) {
|
||||
return caddyhttp.Error(http.StatusForbidden, err)
|
||||
}
|
||||
@ -611,6 +613,11 @@ func (fsrv *FileServer) mapDirOpenError(fileSystem fs.FS, originalErr error, nam
|
||||
return originalErr
|
||||
}
|
||||
|
||||
var pathErr *fs.PathError
|
||||
if errors.As(originalErr, &pathErr) {
|
||||
return fs.ErrInvalid
|
||||
}
|
||||
|
||||
parts := strings.Split(name, separator)
|
||||
for i := range parts {
|
||||
if parts[i] == "" {
|
||||
|
@ -118,6 +118,11 @@ func (irh interceptedResponseHandler) WriteHeader(statusCode int) {
|
||||
irh.ResponseRecorder.WriteHeader(statusCode)
|
||||
}
|
||||
|
||||
// EXPERIMENTAL: Subject to change or removal.
|
||||
func (irh interceptedResponseHandler) Unwrap() http.ResponseWriter {
|
||||
return irh.ResponseRecorder
|
||||
}
|
||||
|
||||
// EXPERIMENTAL: Subject to change or removal.
|
||||
func (ir Intercept) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
|
||||
buf := bufPool.Get().(*bytes.Buffer)
|
||||
|
@ -353,7 +353,7 @@ func (h *HTTPTransport) NewTransport(caddyCtx caddy.Context) (*http.Transport, e
|
||||
h.NetworkProxyRaw = caddyconfig.JSONModuleObject(u, "from", "url", nil)
|
||||
}
|
||||
if len(h.NetworkProxyRaw) != 0 {
|
||||
proxyMod, err := caddyCtx.LoadModule(h, "ForwardProxyRaw")
|
||||
proxyMod, err := caddyCtx.LoadModule(h, "NetworkProxyRaw")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load network_proxy module: %v", err)
|
||||
}
|
||||
@ -382,6 +382,36 @@ func (h *HTTPTransport) NewTransport(caddyCtx caddy.Context) (*http.Transport, e
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("making TLS client config: %v", err)
|
||||
}
|
||||
|
||||
// servername has a placeholder, so we need to replace it
|
||||
if strings.Contains(h.TLS.ServerName, "{") {
|
||||
rt.DialTLSContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
// reuses the dialer from above to establish a plaintext connection
|
||||
conn, err := dialContext(ctx, network, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// but add our own handshake logic
|
||||
repl := ctx.Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
|
||||
tlsConfig := rt.TLSClientConfig.Clone()
|
||||
tlsConfig.ServerName = repl.ReplaceAll(tlsConfig.ServerName, "")
|
||||
tlsConn := tls.Client(conn, tlsConfig)
|
||||
|
||||
// complete the handshake before returning the connection
|
||||
if rt.TLSHandshakeTimeout != 0 {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithTimeout(ctx, rt.TLSHandshakeTimeout)
|
||||
defer cancel()
|
||||
}
|
||||
err = tlsConn.HandshakeContext(ctx)
|
||||
if err != nil {
|
||||
_ = tlsConn.Close()
|
||||
return nil, err
|
||||
}
|
||||
return tlsConn, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if h.KeepAlive != nil {
|
||||
@ -453,45 +483,9 @@ func (h *HTTPTransport) NewTransport(caddyCtx caddy.Context) (*http.Transport, e
|
||||
return rt, nil
|
||||
}
|
||||
|
||||
// replaceTLSServername checks TLS servername to see if it needs replacing
|
||||
// if it does need replacing, it creates a new cloned HTTPTransport object to avoid any races
|
||||
// and does the replacing of the TLS servername on that and returns the new object
|
||||
// if no replacement is necessary it returns the original
|
||||
func (h *HTTPTransport) replaceTLSServername(repl *caddy.Replacer) *HTTPTransport {
|
||||
// check whether we have TLS and need to replace the servername in the TLSClientConfig
|
||||
if h.TLSEnabled() && strings.Contains(h.TLS.ServerName, "{") {
|
||||
// make a new h, "copy" the parts we don't need to touch, add a new *tls.Config and replace servername
|
||||
newtransport := &HTTPTransport{
|
||||
Resolver: h.Resolver,
|
||||
TLS: h.TLS,
|
||||
KeepAlive: h.KeepAlive,
|
||||
Compression: h.Compression,
|
||||
MaxConnsPerHost: h.MaxConnsPerHost,
|
||||
DialTimeout: h.DialTimeout,
|
||||
FallbackDelay: h.FallbackDelay,
|
||||
ResponseHeaderTimeout: h.ResponseHeaderTimeout,
|
||||
ExpectContinueTimeout: h.ExpectContinueTimeout,
|
||||
MaxResponseHeaderSize: h.MaxResponseHeaderSize,
|
||||
WriteBufferSize: h.WriteBufferSize,
|
||||
ReadBufferSize: h.ReadBufferSize,
|
||||
Versions: h.Versions,
|
||||
Transport: h.Transport.Clone(),
|
||||
h2cTransport: h.h2cTransport,
|
||||
}
|
||||
newtransport.Transport.TLSClientConfig.ServerName = repl.ReplaceAll(newtransport.Transport.TLSClientConfig.ServerName, "")
|
||||
return newtransport
|
||||
}
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
// RoundTrip implements http.RoundTripper.
|
||||
func (h *HTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
// Try to replace TLS servername if needed
|
||||
repl := req.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
|
||||
transport := h.replaceTLSServername(repl)
|
||||
|
||||
transport.SetScheme(req)
|
||||
h.SetScheme(req)
|
||||
|
||||
// use HTTP/3 if enabled (TODO: This is EXPERIMENTAL)
|
||||
if h.h3Transport != nil {
|
||||
@ -507,7 +501,7 @@ func (h *HTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return h.h2cTransport.RoundTrip(req)
|
||||
}
|
||||
|
||||
return transport.Transport.RoundTrip(req)
|
||||
return h.Transport.RoundTrip(req)
|
||||
}
|
||||
|
||||
// SetScheme ensures that the outbound request req
|
||||
|
@ -91,8 +91,7 @@ func parseACMEServer(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
|
||||
acmeServer.Policy.AllowWildcardNames = true
|
||||
case "allow":
|
||||
r := &RuleSet{}
|
||||
for h.Next() {
|
||||
for h.NextBlock(h.Nesting() - 1) {
|
||||
for nesting := h.Nesting(); h.NextBlock(nesting); {
|
||||
if h.CountRemainingArgs() == 0 {
|
||||
return nil, h.ArgErr() // TODO:
|
||||
}
|
||||
@ -105,15 +104,13 @@ func parseACMEServer(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
|
||||
return nil, h.Errf("unrecognized 'allow' subdirective: %s", h.Val())
|
||||
}
|
||||
}
|
||||
}
|
||||
if acmeServer.Policy == nil {
|
||||
acmeServer.Policy = &Policy{}
|
||||
}
|
||||
acmeServer.Policy.Allow = r
|
||||
case "deny":
|
||||
r := &RuleSet{}
|
||||
for h.Next() {
|
||||
for h.NextBlock(h.Nesting() - 1) {
|
||||
for nesting := h.Nesting(); h.NextBlock(nesting); {
|
||||
if h.CountRemainingArgs() == 0 {
|
||||
return nil, h.ArgErr() // TODO:
|
||||
}
|
||||
@ -126,7 +123,6 @@ func parseACMEServer(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
|
||||
return nil, h.Errf("unrecognized 'deny' subdirective: %s", h.Val())
|
||||
}
|
||||
}
|
||||
}
|
||||
if acmeServer.Policy == nil {
|
||||
acmeServer.Policy = &Policy{}
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ func (iss *ACMEIssuer) makeIssuerTemplate(ctx caddy.Context) (certmagic.ACMEIssu
|
||||
}
|
||||
|
||||
if len(iss.NetworkProxyRaw) != 0 {
|
||||
proxyMod, err := ctx.LoadModule(iss, "ForwardProxyRaw")
|
||||
proxyMod, err := ctx.LoadModule(iss, "NetworkProxyRaw")
|
||||
if err != nil {
|
||||
return template, fmt.Errorf("failed to load network_proxy module: %v", err)
|
||||
}
|
||||
|
@ -144,9 +144,9 @@ func (hcg HTTPCertGetter) GetCertificate(ctx context.Context, hello *tls.ClientH
|
||||
qs.Set("server_name", hello.ServerName)
|
||||
qs.Set("signature_schemes", strings.Join(sigs, ","))
|
||||
qs.Set("cipher_suites", strings.Join(suites, ","))
|
||||
remoteIP, _, err := net.SplitHostPort(hello.Conn.RemoteAddr().String())
|
||||
if err == nil && remoteIP != "" {
|
||||
qs.Set("remote_ip", remoteIP)
|
||||
localIP, _, err := net.SplitHostPort(hello.Conn.LocalAddr().String())
|
||||
if err == nil && localIP != "" {
|
||||
qs.Set("local_ip", localIP)
|
||||
}
|
||||
parsed.RawQuery = qs.Encode()
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user