mirror of
https://github.com/caddyserver/caddy.git
synced 2026-05-26 00:32:31 -04:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6d9a83376b | |||
| df5edf6bdb | |||
| 908e956927 | |||
| 2f7ceb5774 | |||
| e89c9a45b9 | |||
| e9ac48b4be | |||
| e55570298a | |||
| 87f63b125b | |||
| 801ec75669 | |||
| c8219d0e95 | |||
| 36fce3fa18 | |||
| 547f069564 | |||
| d9fbef92fc | |||
| 1a4c857bb9 | |||
| 65c489a0c3 | |||
| db55da59ef | |||
| b4c7313cc7 | |||
| b809ed71ed | |||
| 0259853a41 | |||
| f0ea489d89 | |||
| 648207063e | |||
| 9782ea3400 | |||
| 11a082c060 | |||
| 15adb893d5 | |||
| 16834d64de | |||
| ec2de22ab1 | |||
| 979c413f04 | |||
| ae5e2d96b7 |
@@ -16,7 +16,6 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
goos:
|
||||
- 'aix'
|
||||
- 'android'
|
||||
- 'linux'
|
||||
- 'solaris'
|
||||
@@ -63,12 +62,11 @@ jobs:
|
||||
env:
|
||||
CGO_ENABLED: 0
|
||||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: ${{ matrix.goos == 'aix' && 'ppc64' || 'amd64' }}
|
||||
shell: bash
|
||||
continue-on-error: true
|
||||
working-directory: ./cmd/caddy
|
||||
run: |
|
||||
GOOS=$GOOS GOARCH=$GOARCH go build -trimpath -o caddy-"$GOOS"-$GOARCH 2> /dev/null
|
||||
GOOS=$GOOS go build -trimpath -o caddy-"$GOOS"-amd64 2> /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "::warning ::$GOOS Build Failed"
|
||||
exit 0
|
||||
|
||||
@@ -55,7 +55,6 @@ func init() {
|
||||
if env, exists := os.LookupEnv("CADDY_ADMIN"); exists {
|
||||
DefaultAdminListen = env
|
||||
}
|
||||
RegisterNamespace("caddy.config_loaders", []interface{}{(*ConfigLoader)(nil)})
|
||||
}
|
||||
|
||||
// AdminConfig configures Caddy's API endpoint, which is used
|
||||
|
||||
@@ -41,15 +41,6 @@ import (
|
||||
"github.com/caddyserver/caddy/v2/notify"
|
||||
)
|
||||
|
||||
func init() {
|
||||
RegisterNamespace("", []interface{}{
|
||||
(*App)(nil),
|
||||
})
|
||||
RegisterNamespace("caddy.storage", []interface{}{
|
||||
(*StorageConverter)(nil),
|
||||
})
|
||||
}
|
||||
|
||||
// Config is the top (or beginning) of the Caddy configuration structure.
|
||||
// Caddy config is expressed natively as a JSON document. If you prefer
|
||||
// not to work with JSON directly, there are [many config adapters](/docs/config-adapters)
|
||||
@@ -81,15 +72,11 @@ type Config struct {
|
||||
// module is `caddy.storage.file_system` (the local file system),
|
||||
// and the default path
|
||||
// [depends on the OS and environment](/docs/conventions#data-directory).
|
||||
// A storage `module` should implement the following interfaces:
|
||||
// - [StorageConverter](https://pkg.go.dev/github.com/caddyserver/caddy/v2#StorageConverter)
|
||||
StorageRaw json.RawMessage `json:"storage,omitempty" caddy:"namespace=caddy.storage inline_key=module"`
|
||||
|
||||
// AppsRaw are the apps that Caddy will load and run. The
|
||||
// app module name is the key, and the app's config is the
|
||||
// associated value.
|
||||
// An `app` should implement the following interfaces:
|
||||
// - [caddy.App](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#App)
|
||||
AppsRaw ModuleMap `json:"apps,omitempty" caddy:"namespace="`
|
||||
|
||||
apps map[string]App
|
||||
@@ -838,18 +825,13 @@ func ParseDuration(s string) (time.Duration, error) {
|
||||
// regardless of storage configuration, since each instance is intended to
|
||||
// have its own unique ID.
|
||||
func InstanceID() (uuid.UUID, error) {
|
||||
appDataDir := AppDataDir()
|
||||
uuidFilePath := filepath.Join(appDataDir, "instance.uuid")
|
||||
uuidFilePath := filepath.Join(AppDataDir(), "instance.uuid")
|
||||
uuidFileBytes, err := os.ReadFile(uuidFilePath)
|
||||
if os.IsNotExist(err) {
|
||||
uuid, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
return uuid, err
|
||||
}
|
||||
err = os.MkdirAll(appDataDir, 0o600)
|
||||
if err != nil {
|
||||
return uuid, err
|
||||
}
|
||||
err = os.WriteFile(uuidFilePath, []byte(uuid.String()), 0o600)
|
||||
return uuid, err
|
||||
} else if err != nil {
|
||||
|
||||
@@ -64,7 +64,6 @@ func placeholderShorthands() []string {
|
||||
"{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}",
|
||||
"{tls_client_fingerprint}", "{http.request.tls.client.fingerprint}",
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
_ "github.com/caddyserver/caddy/v2/modules/standard"
|
||||
)
|
||||
|
||||
// Validates that Caddy's registered internal modules implement the necessary interfaces of their
|
||||
// respective namespaces
|
||||
func TestTypes(t *testing.T) {
|
||||
var i int
|
||||
for _, v := range caddy.Modules() {
|
||||
mod, _ := caddy.GetModule(v)
|
||||
if ok, err := caddy.ConformsToNamespace(mod.New(), mod.ID.Namespace()); !ok {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
i++
|
||||
}
|
||||
t.Logf("Passed through %d modules", i)
|
||||
}
|
||||
+3
-4
@@ -200,10 +200,9 @@ func cmdExportStorage(fl Flags) (int, error) {
|
||||
}
|
||||
|
||||
hdr := &tar.Header{
|
||||
Name: k,
|
||||
Mode: 0o600,
|
||||
Size: int64(len(v)),
|
||||
ModTime: info.Modified,
|
||||
Name: k,
|
||||
Mode: 0o600,
|
||||
Size: int64(len(v)),
|
||||
}
|
||||
|
||||
if err = tw.WriteHeader(hdr); err != nil {
|
||||
|
||||
@@ -14,6 +14,7 @@ require (
|
||||
github.com/google/uuid v1.3.1
|
||||
github.com/klauspost/compress v1.17.0
|
||||
github.com/klauspost/cpuid/v2 v2.2.5
|
||||
github.com/mastercactapus/proxyprotocol v0.0.4
|
||||
github.com/mholt/acmez v1.2.0
|
||||
github.com/prometheus/client_golang v1.15.1
|
||||
github.com/quic-go/quic-go v0.40.0
|
||||
@@ -116,7 +117,6 @@ require (
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-ps v1.0.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/pires/go-proxyproto v0.7.0
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/prometheus/client_model v0.4.0 // indirect
|
||||
github.com/prometheus/common v0.42.0 // indirect
|
||||
|
||||
@@ -352,6 +352,8 @@ github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0Q
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
|
||||
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
|
||||
github.com/mastercactapus/proxyprotocol v0.0.4 h1:qSY75IZF30ZqIU9iW1ip3I7gTnm8wRAnGWqPxCBVgq0=
|
||||
github.com/mastercactapus/proxyprotocol v0.0.4/go.mod h1:X8FRVEDZz9FkrIoL4QYTBF4Ka4ELwTv0sah0/5NxCPw=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
@@ -431,8 +433,6 @@ github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9
|
||||
github.com/peterbourgon/diskv/v3 v3.0.1 h1:x06SQA46+PKIUftmEujdwSEpIx8kR+M9eLYsUxeYveU=
|
||||
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs=
|
||||
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
|
||||
@@ -37,12 +37,6 @@ import (
|
||||
"github.com/caddyserver/caddy/v2/internal"
|
||||
)
|
||||
|
||||
func init() {
|
||||
RegisterNamespace("caddy.listeners", []interface{}{
|
||||
(*ListenerWrapper)(nil),
|
||||
})
|
||||
}
|
||||
|
||||
// NetworkAddress represents one or more network addresses.
|
||||
// It contains the individual components for a parsed network
|
||||
// address of the form accepted by ParseNetworkAddress().
|
||||
|
||||
@@ -33,12 +33,6 @@ func init() {
|
||||
RegisterModule(StdoutWriter{})
|
||||
RegisterModule(StderrWriter{})
|
||||
RegisterModule(DiscardWriter{})
|
||||
RegisterNamespace("caddy.logging.encoders", []interface{}{
|
||||
(*zapcore.Encoder)(nil),
|
||||
})
|
||||
RegisterNamespace("caddy.logging.writers", []interface{}{
|
||||
(*WriterOpener)(nil),
|
||||
})
|
||||
}
|
||||
|
||||
// Logging facilitates logging within Caddy. The default log is
|
||||
@@ -271,8 +265,6 @@ type BaseLog struct {
|
||||
WriterRaw json.RawMessage `json:"writer,omitempty" caddy:"namespace=caddy.logging.writers inline_key=output"`
|
||||
|
||||
// The encoder is how the log entries are formatted or encoded.
|
||||
// An `encoder` should implement the following interfaces:
|
||||
// - [zapcore.Encoder](https://pkg.go.dev/go.uber.org/zap/zapcore#Encoder)
|
||||
EncoderRaw json.RawMessage `json:"encoder,omitempty" caddy:"namespace=caddy.logging.encoders inline_key=format"`
|
||||
|
||||
// Level is the minimum level to emit, and is inclusive.
|
||||
|
||||
@@ -31,13 +31,6 @@ import (
|
||||
|
||||
func init() {
|
||||
caddy.RegisterModule(HTTPBasicAuth{})
|
||||
|
||||
caddy.RegisterNamespace("http.authentication.hashes", []interface{}{
|
||||
(*Comparer)(nil),
|
||||
})
|
||||
caddy.RegisterNamespace("http.authentication.providers", []interface{}{
|
||||
(*Authenticator)(nil),
|
||||
})
|
||||
}
|
||||
|
||||
// HTTPBasicAuth facilitates HTTP basic authentication.
|
||||
|
||||
@@ -37,9 +37,6 @@ import (
|
||||
|
||||
func init() {
|
||||
caddy.RegisterModule(Encode{})
|
||||
caddy.RegisterNamespace("http.encoders", []interface{}{
|
||||
(*Encoding)(nil),
|
||||
})
|
||||
}
|
||||
|
||||
// Encode is a middleware which can encode responses.
|
||||
|
||||
@@ -16,7 +16,6 @@ package fileserver
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
@@ -32,14 +31,13 @@ import (
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
"github.com/caddyserver/caddy/v2/caddyconfig"
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp/encode"
|
||||
caddytpl "github.com/caddyserver/caddy/v2/modules/caddyhttp/templates"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caddycmd.RegisterCommand(caddycmd.Command{
|
||||
Name: "file-server",
|
||||
Usage: "[--domain <example.com>] [--root <path>] [--listen <addr>] [--browse] [--access-log] [--precompressed]",
|
||||
Usage: "[--domain <example.com>] [--root <path>] [--listen <addr>] [--browse] [--access-log]",
|
||||
Short: "Spins up a production-ready file server",
|
||||
Long: `
|
||||
A simple but production-ready file server. Useful for quick deployments,
|
||||
@@ -52,9 +50,6 @@ will be changed to the HTTPS port and the server will use HTTPS. If using
|
||||
a public domain, ensure A/AAAA records are properly configured before
|
||||
using this option.
|
||||
|
||||
By default, Zstandard and Gzip compression are enabled. Use --no-compress
|
||||
to disable compression.
|
||||
|
||||
If --browse is enabled, requests for folders without an index file will
|
||||
respond with a file listing.`,
|
||||
CobraFunc: func(cmd *cobra.Command) {
|
||||
@@ -65,8 +60,6 @@ respond with a file listing.`,
|
||||
cmd.Flags().BoolP("templates", "t", false, "Enable template rendering")
|
||||
cmd.Flags().BoolP("access-log", "a", false, "Enable the access log")
|
||||
cmd.Flags().BoolP("debug", "v", false, "Enable verbose debug logs")
|
||||
cmd.Flags().BoolP("no-compress", "", false, "Disable Zstandard and Gzip compression")
|
||||
cmd.Flags().StringSliceP("precompressed", "p", []string{}, "Specify precompression file extensions. Compression preference implied from flag order.")
|
||||
cmd.RunE = caddycmd.WrapCommandFuncForCobra(cmdFileServer)
|
||||
cmd.AddCommand(&cobra.Command{
|
||||
Use: "export-template",
|
||||
@@ -91,64 +84,15 @@ func cmdFileServer(fs caddycmd.Flags) (int, error) {
|
||||
templates := fs.Bool("templates")
|
||||
accessLog := fs.Bool("access-log")
|
||||
debug := fs.Bool("debug")
|
||||
compress := !fs.Bool("no-compress")
|
||||
precompressed, err := fs.GetStringSlice("precompressed")
|
||||
if err != nil {
|
||||
return caddy.ExitCodeFailedStartup, fmt.Errorf("invalid precompressed flag: %v", err)
|
||||
}
|
||||
|
||||
var handlers []json.RawMessage
|
||||
|
||||
if compress {
|
||||
zstd, err := caddy.GetModule("http.encoders.zstd")
|
||||
if err != nil {
|
||||
return caddy.ExitCodeFailedStartup, err
|
||||
}
|
||||
|
||||
gzip, err := caddy.GetModule("http.encoders.gzip")
|
||||
if err != nil {
|
||||
return caddy.ExitCodeFailedStartup, err
|
||||
}
|
||||
|
||||
handlers = append(handlers, caddyconfig.JSONModuleObject(encode.Encode{
|
||||
EncodingsRaw: caddy.ModuleMap{
|
||||
"zstd": caddyconfig.JSON(zstd.New(), nil),
|
||||
"gzip": caddyconfig.JSON(gzip.New(), nil),
|
||||
},
|
||||
Prefer: []string{"zstd", "gzip"},
|
||||
}, "handler", "encode", nil))
|
||||
}
|
||||
|
||||
if templates {
|
||||
handler := caddytpl.Templates{FileRoot: root}
|
||||
handlers = append(handlers, caddyconfig.JSONModuleObject(handler, "handler", "templates", nil))
|
||||
}
|
||||
|
||||
handler := FileServer{Root: root}
|
||||
|
||||
if len(precompressed) != 0 {
|
||||
// logic mirrors modules/caddyhttp/fileserver/caddyfile.go case "precompressed"
|
||||
var order []string
|
||||
for _, compression := range precompressed {
|
||||
modID := "http.precompressed." + compression
|
||||
mod, err := caddy.GetModule(modID)
|
||||
if err != nil {
|
||||
return caddy.ExitCodeFailedStartup, fmt.Errorf("getting module named '%s': %v", modID, err)
|
||||
}
|
||||
inst := mod.New()
|
||||
precompress, ok := inst.(encode.Precompressed)
|
||||
if !ok {
|
||||
return caddy.ExitCodeFailedStartup, fmt.Errorf("module %s is not a precompressor; is %T", modID, inst)
|
||||
}
|
||||
if handler.PrecompressedRaw == nil {
|
||||
handler.PrecompressedRaw = make(caddy.ModuleMap)
|
||||
}
|
||||
handler.PrecompressedRaw[compression] = caddyconfig.JSON(precompress, nil)
|
||||
order = append(order, compression)
|
||||
}
|
||||
handler.PrecompressedOrder = order
|
||||
}
|
||||
|
||||
if browse {
|
||||
handler.Browse = new(Browse)
|
||||
}
|
||||
@@ -210,7 +154,7 @@ func cmdFileServer(fs caddycmd.Flags) (int, error) {
|
||||
}
|
||||
}
|
||||
|
||||
err = caddy.Run(cfg)
|
||||
err := caddy.Run(cfg)
|
||||
if err != nil {
|
||||
return caddy.ExitCodeFailedStartup, err
|
||||
}
|
||||
|
||||
@@ -38,10 +38,6 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
caddy.RegisterNamespace("http.precompressed", []interface{}{
|
||||
(*encode.Precompressed)(nil),
|
||||
})
|
||||
|
||||
caddy.RegisterModule(FileServer{})
|
||||
}
|
||||
|
||||
|
||||
@@ -151,18 +151,6 @@ func (e *ExtraLogFields) Add(field zap.Field) {
|
||||
e.fields = append(e.fields, field)
|
||||
}
|
||||
|
||||
// Set sets a field in the list of extra fields to log.
|
||||
// If the field already exists, it is replaced.
|
||||
func (e *ExtraLogFields) Set(field zap.Field) {
|
||||
for i := range e.fields {
|
||||
if e.fields[i].Key == field.Key {
|
||||
e.fields[i] = field
|
||||
return
|
||||
}
|
||||
}
|
||||
e.fields = append(e.fields, field)
|
||||
}
|
||||
|
||||
const (
|
||||
// Variable name used to indicate that this request
|
||||
// should be omitted from the access logs
|
||||
|
||||
@@ -197,8 +197,6 @@ type (
|
||||
// where each of the array elements is a matcher set, i.e. an
|
||||
// object keyed by matcher name.
|
||||
MatchNot struct {
|
||||
// A `matcher` should implement the following interfaces:
|
||||
// - [caddyhttp.RequestMatcher](https://pkg.go.dev/github.com/caddyserver/caddy/v2/modules/caddyhttp?tab=doc#RequestMatcher)
|
||||
MatcherSetsRaw []caddy.ModuleMap `json:"-" caddy:"namespace=http.matchers"`
|
||||
MatcherSets []MatcherSet `json:"-"`
|
||||
}
|
||||
@@ -214,9 +212,6 @@ func init() {
|
||||
caddy.RegisterModule(MatchHeaderRE{})
|
||||
caddy.RegisterModule(new(MatchProtocol))
|
||||
caddy.RegisterModule(MatchNot{})
|
||||
caddy.RegisterNamespace("http.matchers", []interface{}{
|
||||
(*RequestMatcher)(nil),
|
||||
})
|
||||
}
|
||||
|
||||
// CaddyModule returns the Caddy module information.
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
package proxyprotocol
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
goproxy "github.com/pires/go-proxyproto"
|
||||
"github.com/mastercactapus/proxyprotocol"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
)
|
||||
@@ -38,74 +38,32 @@ type ListenerWrapper struct {
|
||||
// Allow is an optional list of CIDR ranges to
|
||||
// allow/require PROXY headers from.
|
||||
Allow []string `json:"allow,omitempty"`
|
||||
allow []netip.Prefix
|
||||
|
||||
// Denby is an optional list of CIDR ranges to
|
||||
// deny PROXY headers from.
|
||||
Deny []string `json:"deny,omitempty"`
|
||||
deny []netip.Prefix
|
||||
|
||||
// Accepted values are: ignore, use, reject, require, skip
|
||||
// default: ignore
|
||||
// Policy definitions are here: https://pkg.go.dev/github.com/pires/go-proxyproto@v0.7.0#Policy
|
||||
FallbackPolicy Policy `json:"fallback_policy,omitempty"`
|
||||
|
||||
policy goproxy.PolicyFunc
|
||||
rules []proxyprotocol.Rule
|
||||
}
|
||||
|
||||
// Provision sets up the listener wrapper.
|
||||
func (pp *ListenerWrapper) Provision(ctx caddy.Context) error {
|
||||
for _, cidr := range pp.Allow {
|
||||
ipnet, err := netip.ParsePrefix(cidr)
|
||||
rules := make([]proxyprotocol.Rule, 0, len(pp.Allow))
|
||||
for _, s := range pp.Allow {
|
||||
_, n, err := net.ParseCIDR(s)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("invalid subnet '%s': %w", s, err)
|
||||
}
|
||||
pp.allow = append(pp.allow, ipnet)
|
||||
rules = append(rules, proxyprotocol.Rule{
|
||||
Timeout: time.Duration(pp.Timeout),
|
||||
Subnet: n,
|
||||
})
|
||||
}
|
||||
for _, cidr := range pp.Deny {
|
||||
ipnet, err := netip.ParsePrefix(cidr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pp.deny = append(pp.deny, ipnet)
|
||||
}
|
||||
pp.policy = func(upstream net.Addr) (goproxy.Policy, error) {
|
||||
// trust unix sockets
|
||||
if network := upstream.Network(); caddy.IsUnixNetwork(network) {
|
||||
return goproxy.USE, nil
|
||||
}
|
||||
ret := pp.FallbackPolicy
|
||||
host, _, err := net.SplitHostPort(upstream.String())
|
||||
if err != nil {
|
||||
return goproxy.REJECT, err
|
||||
}
|
||||
|
||||
ip, err := netip.ParseAddr(host)
|
||||
if err != nil {
|
||||
return goproxy.REJECT, err
|
||||
}
|
||||
for _, ipnet := range pp.deny {
|
||||
if ipnet.Contains(ip) {
|
||||
return goproxy.REJECT, nil
|
||||
}
|
||||
}
|
||||
for _, ipnet := range pp.allow {
|
||||
if ipnet.Contains(ip) {
|
||||
ret = PolicyUSE
|
||||
break
|
||||
}
|
||||
}
|
||||
return policyToGoProxyPolicy[ret], nil
|
||||
}
|
||||
pp.rules = rules
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WrapListener adds PROXY protocol support to the listener.
|
||||
func (pp *ListenerWrapper) WrapListener(l net.Listener) net.Listener {
|
||||
pl := &goproxy.Listener{
|
||||
Listener: l,
|
||||
ReadHeaderTimeout: time.Duration(pp.Timeout),
|
||||
}
|
||||
pl.Policy = pp.policy
|
||||
pl := proxyprotocol.NewListener(l, time.Duration(pp.Timeout))
|
||||
pl.SetFilter(pp.rules)
|
||||
return pl
|
||||
}
|
||||
|
||||
@@ -35,8 +35,6 @@ func (ListenerWrapper) CaddyModule() caddy.ModuleInfo {
|
||||
// proxy_protocol {
|
||||
// timeout <duration>
|
||||
// allow <IPs...>
|
||||
// deny <IPs...>
|
||||
// fallback_policy <policy>
|
||||
// }
|
||||
func (w *ListenerWrapper) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||
for d.Next() {
|
||||
@@ -59,17 +57,7 @@ func (w *ListenerWrapper) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||
|
||||
case "allow":
|
||||
w.Allow = append(w.Allow, d.RemainingArgs()...)
|
||||
case "deny":
|
||||
w.Deny = append(w.Deny, d.RemainingArgs()...)
|
||||
case "fallback_policy":
|
||||
if !d.NextArg() {
|
||||
return d.ArgErr()
|
||||
}
|
||||
p, err := parsePolicy(d.Val())
|
||||
if err != nil {
|
||||
return d.WrapErr(err)
|
||||
}
|
||||
w.FallbackPolicy = p
|
||||
|
||||
default:
|
||||
return d.ArgErr()
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
package proxyprotocol
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
goproxy "github.com/pires/go-proxyproto"
|
||||
)
|
||||
|
||||
type Policy int
|
||||
|
||||
// as defined in: https://pkg.go.dev/github.com/pires/go-proxyproto@v0.7.0#Policy
|
||||
const (
|
||||
// IGNORE address from PROXY header, but accept connection
|
||||
PolicyIGNORE Policy = iota
|
||||
// USE address from PROXY header
|
||||
PolicyUSE
|
||||
// REJECT connection when PROXY header is sent
|
||||
// Note: even though the first read on the connection returns an error if
|
||||
// a PROXY header is present, subsequent reads do not. It is the task of
|
||||
// the code using the connection to handle that case properly.
|
||||
PolicyREJECT
|
||||
// REQUIRE connection to send PROXY header, reject if not present
|
||||
// Note: even though the first read on the connection returns an error if
|
||||
// a PROXY header is not present, subsequent reads do not. It is the task
|
||||
// of the code using the connection to handle that case properly.
|
||||
PolicyREQUIRE
|
||||
// SKIP accepts a connection without requiring the PROXY header
|
||||
// Note: an example usage can be found in the SkipProxyHeaderForCIDR
|
||||
// function.
|
||||
PolicySKIP
|
||||
)
|
||||
|
||||
var policyToGoProxyPolicy = map[Policy]goproxy.Policy{
|
||||
PolicyUSE: goproxy.USE,
|
||||
PolicyIGNORE: goproxy.IGNORE,
|
||||
PolicyREJECT: goproxy.REJECT,
|
||||
PolicyREQUIRE: goproxy.REQUIRE,
|
||||
PolicySKIP: goproxy.SKIP,
|
||||
}
|
||||
|
||||
var policyMap = map[Policy]string{
|
||||
PolicyUSE: "USE",
|
||||
PolicyIGNORE: "IGNORE",
|
||||
PolicyREJECT: "REJECT",
|
||||
PolicyREQUIRE: "REQUIRE",
|
||||
PolicySKIP: "SKIP",
|
||||
}
|
||||
|
||||
var policyMapRev = map[string]Policy{
|
||||
"USE": PolicyUSE,
|
||||
"IGNORE": PolicyIGNORE,
|
||||
"REJECT": PolicyREJECT,
|
||||
"REQUIRE": PolicyREQUIRE,
|
||||
"SKIP": PolicySKIP,
|
||||
}
|
||||
|
||||
// MarshalText implements the text marshaller method.
|
||||
func (x Policy) MarshalText() ([]byte, error) {
|
||||
return []byte(policyMap[x]), nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements the text unmarshaller method.
|
||||
func (x *Policy) UnmarshalText(text []byte) error {
|
||||
name := string(text)
|
||||
tmp, err := parsePolicy(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*x = tmp
|
||||
return nil
|
||||
}
|
||||
|
||||
func parsePolicy(name string) (Policy, error) {
|
||||
if x, ok := policyMapRev[strings.ToUpper(name)]; ok {
|
||||
return x, nil
|
||||
}
|
||||
return Policy(0), fmt.Errorf("%s is %w", name, errInvalidPolicy)
|
||||
}
|
||||
|
||||
var errInvalidPolicy = errors.New("invalid policy")
|
||||
@@ -40,7 +40,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
"github.com/caddyserver/caddy/v2/modules/caddytls"
|
||||
@@ -158,17 +157,9 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
|
||||
case "http.request.duration_ms":
|
||||
start := GetVar(req.Context(), "start_time").(time.Time)
|
||||
return time.Since(start).Seconds() * 1e3, true // multiply seconds to preserve decimal (see #4666)
|
||||
|
||||
case "http.request.uuid":
|
||||
// fetch the UUID for this request
|
||||
id := GetVar(req.Context(), "uuid").(*requestID)
|
||||
|
||||
// set it to this request's access log
|
||||
extra := req.Context().Value(ExtraLogFieldsCtxKey).(*ExtraLogFields)
|
||||
extra.Set(zap.String("uuid", id.String()))
|
||||
|
||||
return id.String(), true
|
||||
|
||||
case "http.request.body":
|
||||
if req.Body == nil {
|
||||
return "", true
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pires/go-proxyproto"
|
||||
"github.com/mastercactapus/proxyprotocol"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/net/http2"
|
||||
|
||||
@@ -207,42 +207,44 @@ func (h *HTTPTransport) NewTransport(caddyCtx caddy.Context) (*http.Transport, e
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to get proxy protocol info from context")
|
||||
}
|
||||
header := proxyproto.Header{
|
||||
SourceAddr: &net.TCPAddr{
|
||||
IP: proxyProtocolInfo.AddrPort.Addr().AsSlice(),
|
||||
Port: int(proxyProtocolInfo.AddrPort.Port()),
|
||||
Zone: proxyProtocolInfo.AddrPort.Addr().Zone(),
|
||||
},
|
||||
}
|
||||
// The src and dst have to be of the same address family. As we don't know the original
|
||||
// dst address (it's kind of impossible to know) and this address is generally of very
|
||||
|
||||
// The src and dst have to be of the some address family. As we don't know the original
|
||||
// dst address (it's kind of impossible to know) and this address is generelly of very
|
||||
// little interest, we just set it to all zeros.
|
||||
var destIP net.IP
|
||||
switch {
|
||||
case proxyProtocolInfo.AddrPort.Addr().Is4():
|
||||
header.TransportProtocol = proxyproto.TCPv4
|
||||
header.DestinationAddr = &net.TCPAddr{
|
||||
IP: net.IPv4zero,
|
||||
}
|
||||
destIP = net.IPv4zero
|
||||
case proxyProtocolInfo.AddrPort.Addr().Is6():
|
||||
header.TransportProtocol = proxyproto.TCPv6
|
||||
header.DestinationAddr = &net.TCPAddr{
|
||||
IP: net.IPv6zero,
|
||||
}
|
||||
destIP = net.IPv6zero
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected remote addr type in proxy protocol info")
|
||||
}
|
||||
|
||||
// TODO: We should probably migrate away from net.IP to use netip.Addr,
|
||||
// but due to the upstream dependency, we can't do that yet.
|
||||
switch h.ProxyProtocol {
|
||||
case "v1":
|
||||
header.Version = 1
|
||||
header := proxyprotocol.HeaderV1{
|
||||
SrcIP: net.IP(proxyProtocolInfo.AddrPort.Addr().AsSlice()),
|
||||
SrcPort: int(proxyProtocolInfo.AddrPort.Port()),
|
||||
DestIP: destIP,
|
||||
DestPort: 0,
|
||||
}
|
||||
caddyCtx.Logger().Debug("sending proxy protocol header v1", zap.Any("header", header))
|
||||
_, err = header.WriteTo(conn)
|
||||
case "v2":
|
||||
header.Version = 2
|
||||
header := proxyprotocol.HeaderV2{
|
||||
Command: proxyprotocol.CmdProxy,
|
||||
Src: &net.TCPAddr{IP: net.IP(proxyProtocolInfo.AddrPort.Addr().AsSlice()), Port: int(proxyProtocolInfo.AddrPort.Port())},
|
||||
Dest: &net.TCPAddr{IP: destIP, Port: 0},
|
||||
}
|
||||
caddyCtx.Logger().Debug("sending proxy protocol header v2", zap.Any("header", header))
|
||||
_, err = header.WriteTo(conn)
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected proxy protocol version")
|
||||
}
|
||||
_, err = header.WriteTo(conn)
|
||||
|
||||
if err != nil {
|
||||
// identify this error as one that occurred during
|
||||
// dialing, which can be important when trying to
|
||||
|
||||
@@ -45,19 +45,6 @@ import (
|
||||
|
||||
func init() {
|
||||
caddy.RegisterModule(Handler{})
|
||||
|
||||
caddy.RegisterNamespace("http.reverse_proxy.circuit_breakers", []interface{}{
|
||||
(*CircuitBreaker)(nil),
|
||||
})
|
||||
caddy.RegisterNamespace("http.reverse_proxy.selection_policies", []interface{}{
|
||||
(*Selector)(nil),
|
||||
})
|
||||
caddy.RegisterNamespace("http.reverse_proxy.transport", []interface{}{
|
||||
(*http.RoundTripper)(nil),
|
||||
})
|
||||
caddy.RegisterNamespace("http.reverse_proxy.upstreams", []interface{}{
|
||||
(*UpstreamSource)(nil),
|
||||
})
|
||||
}
|
||||
|
||||
// Handler implements a highly configurable and production-ready reverse proxy.
|
||||
|
||||
@@ -22,12 +22,6 @@ import (
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caddy.RegisterNamespace("http.handlers", []interface{}{
|
||||
(*MiddlewareHandler)(nil),
|
||||
})
|
||||
}
|
||||
|
||||
// Route consists of a set of rules for matching HTTP requests,
|
||||
// a list of handlers to execute, and optional flow control
|
||||
// parameters which customize the handling of HTTP requests
|
||||
|
||||
@@ -30,18 +30,6 @@ import (
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caddy.RegisterNamespace("dns.provider", []interface{}{
|
||||
(*acmez.Solver)(nil),
|
||||
})
|
||||
caddy.RegisterNamespace("tls.get_certificate", []interface{}{
|
||||
(*certmagic.Manager)(nil),
|
||||
})
|
||||
caddy.RegisterNamespace("tls.issuance", []interface{}{
|
||||
(*certmagic.Issuer)(nil),
|
||||
})
|
||||
}
|
||||
|
||||
// AutomationConfig governs the automated management of TLS certificates.
|
||||
type AutomationConfig struct {
|
||||
// The list of automation policies. The first policy matching
|
||||
|
||||
@@ -33,9 +33,6 @@ import (
|
||||
|
||||
func init() {
|
||||
caddy.RegisterModule(LeafCertClientAuth{})
|
||||
caddy.RegisterNamespace("tls.handshake_match", []interface{}{
|
||||
(*ConnectionMatcher)(nil),
|
||||
})
|
||||
}
|
||||
|
||||
// ConnectionPolicies govern the establishment of TLS connections. It is
|
||||
|
||||
@@ -28,12 +28,6 @@ import (
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caddy.RegisterNamespace("tls.stek", []interface{}{
|
||||
(*STEKProvider)(nil),
|
||||
})
|
||||
}
|
||||
|
||||
// SessionTicketService configures and manages TLS session tickets.
|
||||
type SessionTicketService struct {
|
||||
// KeySource is the method by which Caddy produces or obtains
|
||||
|
||||
@@ -35,10 +35,6 @@ import (
|
||||
func init() {
|
||||
caddy.RegisterModule(TLS{})
|
||||
caddy.RegisterModule(AutomateLoader{})
|
||||
|
||||
caddy.RegisterNamespace("tls.certificates", []interface{}{
|
||||
(*CertificateLoader)(nil),
|
||||
})
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -656,11 +652,6 @@ func (AutomateLoader) CaddyModule() caddy.ModuleInfo {
|
||||
}
|
||||
}
|
||||
|
||||
// LoadCertificates is a stub so AutomateLoader can implement CertificateLoader
|
||||
func (AutomateLoader) LoadCertificates() ([]Certificate, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// CertCacheOptions configures the certificate cache.
|
||||
type CertCacheOptions struct {
|
||||
// Maximum number of certificates to allow in the
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
package caddy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var namespaceTypes map[string][]reflect.Type = make(map[string][]reflect.Type)
|
||||
|
||||
func RegisterNamespace(namespace string, vals []interface{}) {
|
||||
var types []reflect.Type
|
||||
for _, v := range vals {
|
||||
reflect.TypeOf(v).Elem()
|
||||
}
|
||||
if _, ok := namespaceTypes[namespace]; ok {
|
||||
panic("namespace is already registered")
|
||||
}
|
||||
namespaceTypes[namespace] = types
|
||||
}
|
||||
|
||||
// NamespaceTypes returns a copy of Caddy's namespace->type registry
|
||||
func NamespaceTypes() map[string][]reflect.Type {
|
||||
copy := make(map[string][]reflect.Type)
|
||||
for namespace, typeSlice := range namespaceTypes {
|
||||
copy[namespace] = typeSlice
|
||||
}
|
||||
return copy
|
||||
}
|
||||
|
||||
// ConformsToNamespace validates the given module implements all the mandatory types of a given namespace
|
||||
func ConformsToNamespace(mod Module, namespace string) (bool, error) {
|
||||
modType := reflect.TypeOf(mod)
|
||||
for _, t := range namespaceTypes[namespace] {
|
||||
if !modType.Implements(t) {
|
||||
return false, fmt.Errorf("%s does not implement %s", modType, t)
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
Reference in New Issue
Block a user