Skip to content

Commit 027d215

Browse files
committed
Scaffolding for server
Code for reading dns01proxy configuration from a file, provisioning Caddy guest modules, and starting Caddy.
1 parent ea3e70c commit 027d215

File tree

10 files changed

+836
-2
lines changed

10 files changed

+836
-2
lines changed

app.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package caddydns01proxy
2+
3+
import (
4+
"encoding/json"
5+
6+
"github.com/caddyserver/caddy/v2"
7+
)
8+
9+
func init() {
10+
caddy.RegisterModule(App{})
11+
}
12+
13+
// A Caddy application module that implements the dns01proxy server.
14+
type App struct {
15+
Handler
16+
17+
// The sockets on which to listen.
18+
Listen []string `json:"listen"`
19+
20+
// Configures the set of trusted proxies.
21+
TrustedProxiesRaw json.RawMessage `json:"trusted_proxies,omitempty" caddy:"namespace=http.ip_sources inline_key=source"`
22+
}
23+
24+
var _ caddy.Module = (*App)(nil)
25+
26+
func (App) CaddyModule() caddy.ModuleInfo {
27+
return caddy.ModuleInfo{
28+
ID: "dns01proxy",
29+
New: func() caddy.Module {
30+
return new(App)
31+
},
32+
}
33+
}

caddy_config.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package caddydns01proxy
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/caddyserver/caddy/v2"
7+
"github.com/liujed/caddy-dns01proxy/jsonutil"
8+
)
9+
10+
// A dns01proxy configuration file is the same as the app configuration.
11+
type ConfigFile = App
12+
13+
// Reads a dns01proxy configuration file and returns a corresponding Caddy
14+
// configuration.
15+
func caddyConfigFromConfigFile(path string) (*caddy.Config, error) {
16+
config, err := jsonutil.UnmarshalFromFile[ConfigFile](path)
17+
if err != nil {
18+
return nil, err
19+
}
20+
21+
// TODO: generate a Caddy configuration.
22+
_ = config
23+
24+
return nil, fmt.Errorf("implement me")
25+
}

client_policy.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package caddydns01proxy
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/caddyserver/caddy/v2"
7+
x509policy "github.com/smallstep/certificates/authority/policy"
8+
"github.com/smallstep/certificates/authority/provisioner"
9+
)
10+
11+
// The policy configuration for a user. Specifies the domains at which the user
12+
// is allowed to answer DNS-01 challenges.
13+
type ClientPolicy struct {
14+
// Identifies the client to which this policy applies.
15+
UserID string `json:"user_id"`
16+
17+
AllowDomainsRaw []string `json:"allow_domains,omitempty"`
18+
DenyDomainsRaw []string `json:"deny_domains,omitempty"`
19+
20+
// The policy to be applied to the DNS domains for answering DNS-01
21+
// challenges.
22+
DomainPolicy x509policy.X509Policy `json:"-"`
23+
}
24+
25+
var _ caddy.Provisioner = (*ClientPolicy)(nil)
26+
27+
func (c *ClientPolicy) Provision(ctx caddy.Context) error {
28+
domainPolicyOpts := provisioner.X509Options{}
29+
30+
provisionX509NameOptions := func(raw *[]string) *x509policy.X509NameOptions {
31+
// Allow the raw version to be GC'd.
32+
defer func() {
33+
*raw = nil
34+
}()
35+
36+
if len(*raw) > 0 {
37+
return &x509policy.X509NameOptions{
38+
DNSDomains: *raw,
39+
}
40+
}
41+
return nil
42+
}
43+
44+
// Ingest the allow/deny lists.
45+
domainPolicyOpts.AllowedNames = provisionX509NameOptions(&c.AllowDomainsRaw)
46+
domainPolicyOpts.DeniedNames = provisionX509NameOptions(&c.DenyDomainsRaw)
47+
48+
// Instantiate the domain policy.
49+
var err error
50+
c.DomainPolicy, err = x509policy.NewX509PolicyEngine(&domainPolicyOpts)
51+
if err != nil {
52+
return fmt.Errorf("unable to provision domain policy: %w", err)
53+
}
54+
55+
return nil
56+
}

client_registry.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package caddydns01proxy
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/caddyserver/caddy/v2"
7+
"github.com/liujed/goutil/maps"
8+
)
9+
10+
// A registry of known users and their corresponding policy configuration.
11+
type ClientRegistry struct {
12+
// Maps each client's user ID to its policy configuration.
13+
Clients maps.Map[string, *ClientPolicy]
14+
}
15+
16+
func (c *ClientRegistry) Provision(
17+
ctx caddy.Context,
18+
accountsRaw []RawAccount,
19+
) error {
20+
// Convert accountsRaw into a map keyed on user ID.
21+
c.Clients = maps.NewHashMap[string, *ClientPolicy]()
22+
for i, rawAccount := range accountsRaw {
23+
if c.Clients.ContainsKey(rawAccount.UserID) {
24+
return fmt.Errorf(
25+
"account %d: user ID is not unique: %q",
26+
i,
27+
rawAccount.UserID,
28+
)
29+
}
30+
31+
c.Clients.Put(rawAccount.UserID, &rawAccount.ClientPolicy)
32+
}
33+
34+
// Provision the ClientPolicy instances.
35+
for userID, ca := range c.Clients.Entries() {
36+
err := ca.Provision(ctx)
37+
if err != nil {
38+
return fmt.Errorf(
39+
"unable to provision client policy for user ID %q: %w",
40+
userID,
41+
err,
42+
)
43+
}
44+
}
45+
46+
return nil
47+
}

command.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,20 @@ Designed to work with:
6363
}
6464

6565
func cmdRun(fs caddycmd.Flags) (int, error) {
66-
return caddy.ExitCodeSuccess, nil
66+
caddy.TrapSignals()
67+
68+
configFlag := fs.String(flgConfig.Name)
69+
cfg, err := caddyConfigFromConfigFile(configFlag)
70+
if err != nil {
71+
return caddy.ExitCodeFailedStartup, err
72+
}
73+
74+
caddy.Log().Info(fmt.Sprintf("Starting %s", Release()))
75+
76+
err = caddy.Run(cfg)
77+
if err != nil {
78+
return caddy.ExitCodeFailedStartup, err
79+
}
80+
81+
select {}
6782
}

dns_config.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package caddydns01proxy
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
7+
"github.com/caddyserver/caddy/v2"
8+
"github.com/caddyserver/certmagic"
9+
"github.com/liujed/goutil/optionals"
10+
)
11+
12+
type DNSConfig struct {
13+
ProviderRaw json.RawMessage `json:"provider" caddy:"namespace=dns.providers inline_key=name"`
14+
15+
Provider certmagic.DNSProvider `json:"-"`
16+
17+
// The TTL to use for the DNS TXT records when answering challenges.
18+
TTL optionals.Optional[caddy.Duration] `json:"ttl"`
19+
}
20+
21+
var _ caddy.Provisioner = (*Handler)(nil)
22+
23+
func (d *DNSConfig) Provision(ctx caddy.Context) error {
24+
if len(d.ProviderRaw) == 0 {
25+
return fmt.Errorf("must configure a DNS provider")
26+
}
27+
28+
module, err := ctx.LoadModule(d, "ProviderRaw")
29+
if err != nil {
30+
return fmt.Errorf("unable to load DNS provider: %w", err)
31+
}
32+
d.Provider = module.(certmagic.DNSProvider)
33+
34+
return nil
35+
}

go.mod

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,98 @@ go 1.24.3
44

55
require (
66
github.com/caddyserver/caddy/v2 v2.10.0
7+
github.com/caddyserver/certmagic v0.23.0
78
github.com/liujed/goutil v0.0.0
9+
github.com/smallstep/certificates v0.26.1
810
github.com/spf13/cobra v1.9.1
911
github.com/spf13/pflag v1.0.6
1012
)
1113

1214
require (
15+
cel.dev/expr v0.19.1 // indirect
16+
dario.cat/mergo v1.0.1 // indirect
17+
filippo.io/edwards25519 v1.1.0 // indirect
18+
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
1319
github.com/KimMachineGun/automemlimit v0.7.1 // indirect
20+
github.com/Masterminds/goutils v1.1.1 // indirect
21+
github.com/Masterminds/semver/v3 v3.3.0 // indirect
22+
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
23+
github.com/Microsoft/go-winio v0.6.0 // indirect
24+
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
1425
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b // indirect
1526
github.com/beorn7/perks v1.0.1 // indirect
16-
github.com/caddyserver/certmagic v0.23.0 // indirect
1727
github.com/caddyserver/zerossl v0.1.3 // indirect
28+
github.com/cespare/xxhash v1.1.0 // indirect
1829
github.com/cespare/xxhash/v2 v2.3.0 // indirect
30+
github.com/chzyer/readline v1.5.1 // indirect
31+
github.com/cloudflare/circl v1.6.0 // indirect
1932
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
33+
github.com/dgraph-io/badger v1.6.2 // indirect
34+
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
35+
github.com/dgraph-io/ristretto v0.2.0 // indirect
36+
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
37+
github.com/dustin/go-humanize v1.0.1 // indirect
2038
github.com/francoispqt/gojay v1.2.13 // indirect
39+
github.com/go-jose/go-jose/v3 v3.0.4 // indirect
40+
github.com/go-kit/kit v0.13.0 // indirect
41+
github.com/go-kit/log v0.2.1 // indirect
42+
github.com/go-logfmt/logfmt v0.6.0 // indirect
43+
github.com/go-sql-driver/mysql v1.7.1 // indirect
2144
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
45+
github.com/golang/protobuf v1.5.4 // indirect
46+
github.com/golang/snappy v0.0.4 // indirect
47+
github.com/google/cel-go v0.24.1 // indirect
2248
github.com/google/pprof v0.0.0-20231212022811-ec68065c825e // indirect
2349
github.com/google/uuid v1.6.0 // indirect
50+
github.com/huandu/xstrings v1.5.0 // indirect
2451
github.com/inconshreveable/mousetrap v1.1.0 // indirect
52+
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
53+
github.com/jackc/pgconn v1.14.3 // indirect
54+
github.com/jackc/pgio v1.0.0 // indirect
55+
github.com/jackc/pgpassfile v1.0.0 // indirect
56+
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
57+
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
58+
github.com/jackc/pgtype v1.14.0 // indirect
59+
github.com/jackc/pgx/v4 v4.18.3 // indirect
60+
github.com/klauspost/compress v1.18.0 // indirect
2561
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
2662
github.com/libdns/libdns v1.0.0-beta.1 // indirect
63+
github.com/manifoldco/promptui v0.9.0 // indirect
64+
github.com/mattn/go-colorable v0.1.13 // indirect
65+
github.com/mattn/go-isatty v0.0.20 // indirect
66+
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
2767
github.com/mholt/acmez/v3 v3.1.2 // indirect
2868
github.com/miekg/dns v1.1.65 // indirect
69+
github.com/mitchellh/copystructure v1.2.0 // indirect
70+
github.com/mitchellh/go-ps v1.0.0 // indirect
71+
github.com/mitchellh/reflectwalk v1.0.2 // indirect
2972
github.com/onsi/ginkgo/v2 v2.13.2 // indirect
3073
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
74+
github.com/pkg/errors v0.9.1 // indirect
3175
github.com/prometheus/client_golang v1.19.1 // indirect
3276
github.com/prometheus/client_model v0.5.0 // indirect
3377
github.com/prometheus/common v0.48.0 // indirect
3478
github.com/prometheus/procfs v0.12.0 // indirect
3579
github.com/quic-go/qpack v0.5.1 // indirect
3680
github.com/quic-go/quic-go v0.50.1 // indirect
81+
github.com/rs/xid v1.5.0 // indirect
3782
github.com/russross/blackfriday/v2 v2.1.0 // indirect
83+
github.com/shopspring/decimal v1.4.0 // indirect
84+
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
85+
github.com/slackhq/nebula v1.6.1 // indirect
86+
github.com/smallstep/nosql v0.6.1 // indirect
87+
github.com/smallstep/pkcs7 v0.0.0-20231024181729-3b98ecc1ca81 // indirect
88+
github.com/smallstep/scep v0.0.0-20231024192529-aee96d7ad34d // indirect
89+
github.com/smallstep/truststore v0.13.0 // indirect
90+
github.com/spf13/cast v1.7.0 // indirect
91+
github.com/stoewer/go-strcase v1.2.0 // indirect
92+
github.com/tailscale/tscert v0.0.0-20240608151842-d3f834017e53 // indirect
93+
github.com/urfave/cli v1.22.14 // indirect
3894
github.com/zeebo/blake3 v0.2.4 // indirect
95+
go.etcd.io/bbolt v1.3.9 // indirect
96+
go.step.sm/cli-utils v0.9.0 // indirect
97+
go.step.sm/crypto v0.45.0 // indirect
98+
go.step.sm/linkedca v0.20.1 // indirect
3999
go.uber.org/automaxprocs v1.6.0 // indirect
40100
go.uber.org/mock v0.5.0 // indirect
41101
go.uber.org/multierr v1.11.0 // indirect
@@ -52,6 +112,10 @@ require (
52112
golang.org/x/text v0.24.0 // indirect
53113
golang.org/x/time v0.11.0 // indirect
54114
golang.org/x/tools v0.32.0 // indirect
115+
google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 // indirect
116+
google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 // indirect
117+
google.golang.org/grpc v1.67.1 // indirect
55118
google.golang.org/protobuf v1.35.1 // indirect
56119
gopkg.in/yaml.v3 v3.0.1 // indirect
120+
howett.net/plist v1.0.0 // indirect
57121
)

0 commit comments

Comments
 (0)