From c5a95c4cd075900e134e1c380342b3738a0a5da5 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Tue, 6 Feb 2024 17:17:59 +0100 Subject: [PATCH] cpanel: remove custom DNS call (#2102) --- cmd/zz_gen_cmd_dnshelp.go | 1 - docs/content/dns/zz_gen_cpanel.md | 3 - providers/dns/cpanel/cpanel.go | 45 +++--- providers/dns/cpanel/cpanel.toml | 3 - providers/dns/cpanel/cpanel_test.go | 143 ++++++++------------ providers/dns/cpanel/internal/shared/dns.go | 67 --------- 6 files changed, 74 insertions(+), 188 deletions(-) delete mode 100644 providers/dns/cpanel/internal/shared/dns.go diff --git a/cmd/zz_gen_cmd_dnshelp.go b/cmd/zz_gen_cmd_dnshelp.go index 39e28944..07626d5b 100644 --- a/cmd/zz_gen_cmd_dnshelp.go +++ b/cmd/zz_gen_cmd_dnshelp.go @@ -621,7 +621,6 @@ func displayDNSHelp(w io.Writer, name string) error { ew.writeln(`Credentials:`) ew.writeln(` - "CPANEL_BASE_URL": API server URL`) - ew.writeln(` - "CPANEL_NAMESERVER": Nameserver`) ew.writeln(` - "CPANEL_TOKEN": API token`) ew.writeln(` - "CPANEL_USERNAME": username`) ew.writeln() diff --git a/docs/content/dns/zz_gen_cpanel.md b/docs/content/dns/zz_gen_cpanel.md index ca8cb06b..a9c3d61d 100644 --- a/docs/content/dns/zz_gen_cpanel.md +++ b/docs/content/dns/zz_gen_cpanel.md @@ -31,7 +31,6 @@ Here is an example bash command using the CPanel/WHM provider: CPANEL_USERNAME = "yyyy" CPANEL_TOKEN = "xxxx" CPANEL_BASE_URL = "https://example.com:2083" \ -CPANEL_NAMESERVER = "ns1.example.com:53" \ lego --email you@example.com --dns cpanel --domains my.example.org run ## WHM @@ -40,7 +39,6 @@ CPANEL_MODE = whm CPANEL_USERNAME = "yyyy" CPANEL_TOKEN = "xxxx" CPANEL_BASE_URL = "https://example.com:2087" \ -CPANEL_NAMESERVER = "ns1.example.com:53" \ lego --email you@example.com --dns cpanel --domains my.example.org run ``` @@ -52,7 +50,6 @@ lego --email you@example.com --dns cpanel --domains my.example.org run | Environment Variable Name | Description | |-----------------------|-------------| | `CPANEL_BASE_URL` | API server URL | -| `CPANEL_NAMESERVER` | Nameserver | | `CPANEL_TOKEN` | API token | | `CPANEL_USERNAME` | username | diff --git a/providers/dns/cpanel/cpanel.go b/providers/dns/cpanel/cpanel.go index c5a13895..333bc689 100644 --- a/providers/dns/cpanel/cpanel.go +++ b/providers/dns/cpanel/cpanel.go @@ -21,11 +21,10 @@ import ( const ( envNamespace = "CPANEL_" - EnvMode = envNamespace + "MODE" - EnvUsername = envNamespace + "USERNAME" - EnvToken = envNamespace + "TOKEN" - EnvBaseURL = envNamespace + "BASE_URL" - EnvNameserver = envNamespace + "NAMESERVER" + EnvMode = envNamespace + "MODE" + EnvUsername = envNamespace + "USERNAME" + EnvToken = envNamespace + "TOKEN" + EnvBaseURL = envNamespace + "BASE_URL" EnvTTL = envNamespace + "TTL" EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT" @@ -46,7 +45,6 @@ type Config struct { Username string Token string BaseURL string - Nameserver string TTL int PropagationTimeout time.Duration PollingInterval time.Duration @@ -58,7 +56,7 @@ func NewDefaultConfig() *Config { return &Config{ Mode: env.GetOrDefaultString(EnvMode, "cpanel"), TTL: env.GetOrDefaultInt(EnvTTL, 300), - PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout), + PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute), PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval), HTTPClient: &http.Client{ Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second), @@ -68,16 +66,15 @@ func NewDefaultConfig() *Config { // DNSProvider implements the challenge.Provider interface. type DNSProvider struct { - config *Config - client apiClient - dnsClient *shared.DNSClient + config *Config + client apiClient } // NewDNSProvider returns a DNSProvider instance configured for CPanel. // Credentials must be passed in the environment variables: // CPANEL_USERNAME, CPANEL_TOKEN, CPANEL_BASE_URL, CPANEL_NAMESERVER. func NewDNSProvider() (*DNSProvider, error) { - values, err := env.Get(EnvUsername, EnvToken, EnvBaseURL, EnvNameserver) + values, err := env.Get(EnvUsername, EnvToken, EnvBaseURL) if err != nil { return nil, fmt.Errorf("cpanel: %w", err) } @@ -86,7 +83,6 @@ func NewDNSProvider() (*DNSProvider, error) { config.Username = values[EnvUsername] config.Token = values[EnvToken] config.BaseURL = values[EnvBaseURL] - config.Nameserver = values[EnvNameserver] return NewDNSProviderConfig(config) } @@ -101,7 +97,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { return nil, errors.New("cpanel: some credentials information are missing") } - if config.BaseURL == "" || config.Nameserver == "" { + if config.BaseURL == "" { return nil, errors.New("cpanel: server information are missing") } @@ -111,9 +107,8 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { } return &DNSProvider{ - config: config, - client: client, - dnsClient: shared.NewDNSClient(10 * time.Second), + config: config, + client: client, }, nil } @@ -128,21 +123,19 @@ func (d *DNSProvider) Present(domain, _, keyAuth string) error { ctx := context.Background() info := dns01.GetChallengeInfo(domain, keyAuth) - effectiveDomain := strings.TrimPrefix(info.EffectiveFQDN, "_acme-challenge.") - - soa, err := d.dnsClient.SOACall(effectiveDomain, d.config.Nameserver) + authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) if err != nil { - return fmt.Errorf("cpanel[mode=%s]: could not find SOA for domain %q (%s) in %s: %w", d.config.Mode, domain, info.EffectiveFQDN, d.config.Nameserver, err) + return fmt.Errorf("arvancloud: could not find zone for domain %q (%s): %w", domain, info.EffectiveFQDN, err) } - zone := dns01.UnFqdn(soa.Hdr.Name) + zone := dns01.UnFqdn(authZone) zoneInfo, err := d.client.FetchZoneInformation(ctx, zone) if err != nil { return fmt.Errorf("cpanel[mode=%s]: fetch zone information: %w", d.config.Mode, err) } - serial, err := getZoneSerial(soa.Hdr.Name, zoneInfo) + serial, err := getZoneSerial(authZone, zoneInfo) if err != nil { return fmt.Errorf("cpanel[mode=%s]: get zone serial: %w", d.config.Mode, err) } @@ -204,19 +197,19 @@ func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error { ctx := context.Background() info := dns01.GetChallengeInfo(domain, keyAuth) - soa, err := d.dnsClient.SOACall(strings.TrimPrefix(info.EffectiveFQDN, "_acme-challenge."), d.config.Nameserver) + authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) if err != nil { - return fmt.Errorf("cpanel[mode=%s]: could not find SOA for domain %q (%s) in %s: %w", d.config.Mode, domain, info.EffectiveFQDN, d.config.Nameserver, err) + return fmt.Errorf("arvancloud: could not find zone for domain %q (%s): %w", domain, info.EffectiveFQDN, err) } - zone := dns01.UnFqdn(soa.Hdr.Name) + zone := dns01.UnFqdn(authZone) zoneInfo, err := d.client.FetchZoneInformation(ctx, zone) if err != nil { return fmt.Errorf("cpanel[mode=%s]: fetch zone information: %w", d.config.Mode, err) } - serial, err := getZoneSerial(soa.Hdr.Name, zoneInfo) + serial, err := getZoneSerial(authZone, zoneInfo) if err != nil { return fmt.Errorf("cpanel[mode=%s]: get zone serial: %w", d.config.Mode, err) } diff --git a/providers/dns/cpanel/cpanel.toml b/providers/dns/cpanel/cpanel.toml index 0f328a96..eac811ef 100644 --- a/providers/dns/cpanel/cpanel.toml +++ b/providers/dns/cpanel/cpanel.toml @@ -10,7 +10,6 @@ Example = ''' CPANEL_USERNAME = "yyyy" CPANEL_TOKEN = "xxxx" CPANEL_BASE_URL = "https://example.com:2083" \ -CPANEL_NAMESERVER = "ns1.example.com:53" \ lego --email you@example.com --dns cpanel --domains my.example.org run ## WHM @@ -19,7 +18,6 @@ CPANEL_MODE = whm CPANEL_USERNAME = "yyyy" CPANEL_TOKEN = "xxxx" CPANEL_BASE_URL = "https://example.com:2087" \ -CPANEL_NAMESERVER = "ns1.example.com:53" \ lego --email you@example.com --dns cpanel --domains my.example.org run ''' @@ -28,7 +26,6 @@ lego --email you@example.com --dns cpanel --domains my.example.org run CPANEL_USERNAME = "username" CPANEL_TOKEN = "API token" CPANEL_BASE_URL = "API server URL" - CPANEL_NAMESERVER = "Nameserver" [Configuration.Additional] CPANEL_MODE = "use cpanel API or WHM API (Default: cpanel)" CPANEL_POLLING_INTERVAL = "Time between DNS propagation check" diff --git a/providers/dns/cpanel/cpanel_test.go b/providers/dns/cpanel/cpanel_test.go index fb39193d..614b9e1c 100644 --- a/providers/dns/cpanel/cpanel_test.go +++ b/providers/dns/cpanel/cpanel_test.go @@ -16,8 +16,7 @@ var envTest = tester.NewEnvTest( EnvMode, EnvUsername, EnvToken, - EnvBaseURL, - EnvNameserver). + EnvBaseURL). WithDomain(envDomain) func TestNewDNSProvider(t *testing.T) { @@ -30,62 +29,47 @@ func TestNewDNSProvider(t *testing.T) { { desc: "success cpanel mode (default)", envVars: map[string]string{ - EnvUsername: "user", - EnvToken: "secret", - EnvBaseURL: "https://example.com", - EnvNameserver: "ns.example.com:53", + EnvUsername: "user", + EnvToken: "secret", + EnvBaseURL: "https://example.com", }, expectedMode: "cpanel", }, { desc: "success whm mode", envVars: map[string]string{ - EnvMode: "whm", - EnvUsername: "user", - EnvToken: "secret", - EnvBaseURL: "https://example.com", - EnvNameserver: "ns.example.com:53", + EnvMode: "whm", + EnvUsername: "user", + EnvToken: "secret", + EnvBaseURL: "https://example.com", }, expectedMode: "whm", }, { desc: "missing user", envVars: map[string]string{ - EnvToken: "secret", - EnvBaseURL: "https://example.com", - EnvNameserver: "ns.example.com:53", + EnvToken: "secret", + EnvBaseURL: "https://example.com", }, expected: "cpanel: some credentials information are missing: CPANEL_USERNAME", }, { desc: "missing token", envVars: map[string]string{ - EnvUsername: "user", - EnvBaseURL: "https://example.com", - EnvNameserver: "ns.example.com:53", + EnvUsername: "user", + EnvBaseURL: "https://example.com", }, expected: "cpanel: some credentials information are missing: CPANEL_TOKEN", }, { desc: "missing base URL", envVars: map[string]string{ - EnvUsername: "user", - EnvToken: "secret", - EnvBaseURL: "", - EnvNameserver: "ns.example.com:53", + EnvUsername: "user", + EnvToken: "secret", + EnvBaseURL: "", }, expected: "cpanel: some credentials information are missing: CPANEL_BASE_URL", }, - { - desc: "missing nameserver", - envVars: map[string]string{ - EnvUsername: "user", - EnvToken: "secret", - EnvBaseURL: "https://example.com", - EnvNameserver: "", - }, - expected: "cpanel: some credentials information are missing: CPANEL_NAMESERVER", - }, } for _, test := range testCases { @@ -111,74 +95,58 @@ func TestNewDNSProvider(t *testing.T) { func TestNewDNSProviderConfig(t *testing.T) { testCases := []struct { - desc string - mode string - username string - token string - baseURL string - nameserver string - expected string + desc string + mode string + username string + token string + baseURL string + expected string }{ { - desc: "success", - mode: "whm", - username: "user", - token: "secret", - baseURL: "https://example.com", - nameserver: "ns.example.com:53", + desc: "success", + mode: "whm", + username: "user", + token: "secret", + baseURL: "https://example.com", }, { - desc: "missing mode", - username: "user", - token: "secret", - baseURL: "https://example.com", - nameserver: "ns.example.com:53", - expected: `cpanel: create client error: unsupported mode: ""`, + desc: "missing mode", + username: "user", + token: "secret", + baseURL: "https://example.com", + expected: `cpanel: create client error: unsupported mode: ""`, }, { - desc: "invalid mode", - mode: "test", - username: "user", - token: "secret", - baseURL: "https://example.com", - nameserver: "ns.example.com:53", - expected: `cpanel: create client error: unsupported mode: "test"`, + desc: "invalid mode", + mode: "test", + username: "user", + token: "secret", + baseURL: "https://example.com", + expected: `cpanel: create client error: unsupported mode: "test"`, }, { - desc: "missing username", - mode: "whm", - username: "", - token: "secret", - baseURL: "https://example.com", - nameserver: "ns.example.com:53", - expected: "cpanel: some credentials information are missing", + desc: "missing username", + mode: "whm", + username: "", + token: "secret", + baseURL: "https://example.com", + expected: "cpanel: some credentials information are missing", }, { - desc: "missing token", - mode: "whm", - username: "user", - token: "", - baseURL: "https://example.com", - nameserver: "ns.example.com:53", - expected: "cpanel: some credentials information are missing", + desc: "missing token", + mode: "whm", + username: "user", + token: "", + baseURL: "https://example.com", + expected: "cpanel: some credentials information are missing", }, { - desc: "missing base URL", - mode: "whm", - username: "user", - token: "secret", - baseURL: "", - nameserver: "ns.example.com:53", - expected: "cpanel: server information are missing", - }, - { - desc: "missing nameserver", - mode: "whm", - username: "user", - token: "secret", - baseURL: "https://example.com", - nameserver: "", - expected: "cpanel: server information are missing", + desc: "missing base URL", + mode: "whm", + username: "user", + token: "secret", + baseURL: "", + expected: "cpanel: server information are missing", }, } @@ -189,7 +157,6 @@ func TestNewDNSProviderConfig(t *testing.T) { config.Username = test.username config.Token = test.token config.BaseURL = test.baseURL - config.Nameserver = test.nameserver p, err := NewDNSProviderConfig(config) diff --git a/providers/dns/cpanel/internal/shared/dns.go b/providers/dns/cpanel/internal/shared/dns.go deleted file mode 100644 index 37127271..00000000 --- a/providers/dns/cpanel/internal/shared/dns.go +++ /dev/null @@ -1,67 +0,0 @@ -package shared - -import ( - "fmt" - "os" - "strconv" - "time" - - "github.com/miekg/dns" -) - -type DNSClient struct { - timeout time.Duration -} - -func NewDNSClient(timeout time.Duration) *DNSClient { - return &DNSClient{timeout: timeout} -} - -func (d DNSClient) SOACall(fqdn, nameserver string) (*dns.SOA, error) { - m := new(dns.Msg) - m.SetQuestion(fqdn, dns.TypeSOA) - m.SetEdns0(4096, false) - - in, err := d.sendDNSQuery(m, nameserver) - if err != nil { - return nil, err - } - - if len(in.Answer) == 0 { - if len(in.Ns) > 0 { - if soa, ok := in.Ns[0].(*dns.SOA); ok && fqdn != soa.Hdr.Name { - return d.SOACall(soa.Hdr.Name, nameserver) - } - } - - return nil, fmt.Errorf("empty answer for %s in %s", fqdn, nameserver) - } - - for _, rr := range in.Answer { - if soa, ok := rr.(*dns.SOA); ok { - return soa, nil - } - } - - return nil, fmt.Errorf("SOA not found for %s in %s", fqdn, nameserver) -} - -func (d DNSClient) sendDNSQuery(m *dns.Msg, ns string) (*dns.Msg, error) { - if ok, _ := strconv.ParseBool(os.Getenv("LEGO_EXPERIMENTAL_DNS_TCP_ONLY")); ok { - tcp := &dns.Client{Net: "tcp", Timeout: d.timeout} - in, _, err := tcp.Exchange(m, ns) - - return in, err - } - - udp := &dns.Client{Net: "udp", Timeout: d.timeout} - in, _, err := udp.Exchange(m, ns) - - if in != nil && in.Truncated { - tcp := &dns.Client{Net: "tcp", Timeout: d.timeout} - // If the TCP request succeeds, the err will reset to nil - in, _, err = tcp.Exchange(m, ns) - } - - return in, err -}