cpanel: remove custom DNS call (#2102)

This commit is contained in:
Ludovic Fernandez 2024-02-06 17:17:59 +01:00 committed by GitHub
parent 83ff393131
commit c5a95c4cd0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 74 additions and 188 deletions

View file

@ -621,7 +621,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln(`Credentials:`) ew.writeln(`Credentials:`)
ew.writeln(` - "CPANEL_BASE_URL": API server URL`) ew.writeln(` - "CPANEL_BASE_URL": API server URL`)
ew.writeln(` - "CPANEL_NAMESERVER": Nameserver`)
ew.writeln(` - "CPANEL_TOKEN": API token`) ew.writeln(` - "CPANEL_TOKEN": API token`)
ew.writeln(` - "CPANEL_USERNAME": username`) ew.writeln(` - "CPANEL_USERNAME": username`)
ew.writeln() ew.writeln()

View file

@ -31,7 +31,6 @@ Here is an example bash command using the CPanel/WHM provider:
CPANEL_USERNAME = "yyyy" CPANEL_USERNAME = "yyyy"
CPANEL_TOKEN = "xxxx" CPANEL_TOKEN = "xxxx"
CPANEL_BASE_URL = "https://example.com:2083" \ 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 lego --email you@example.com --dns cpanel --domains my.example.org run
## WHM ## WHM
@ -40,7 +39,6 @@ CPANEL_MODE = whm
CPANEL_USERNAME = "yyyy" CPANEL_USERNAME = "yyyy"
CPANEL_TOKEN = "xxxx" CPANEL_TOKEN = "xxxx"
CPANEL_BASE_URL = "https://example.com:2087" \ 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 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 | | Environment Variable Name | Description |
|-----------------------|-------------| |-----------------------|-------------|
| `CPANEL_BASE_URL` | API server URL | | `CPANEL_BASE_URL` | API server URL |
| `CPANEL_NAMESERVER` | Nameserver |
| `CPANEL_TOKEN` | API token | | `CPANEL_TOKEN` | API token |
| `CPANEL_USERNAME` | username | | `CPANEL_USERNAME` | username |

View file

@ -25,7 +25,6 @@ const (
EnvUsername = envNamespace + "USERNAME" EnvUsername = envNamespace + "USERNAME"
EnvToken = envNamespace + "TOKEN" EnvToken = envNamespace + "TOKEN"
EnvBaseURL = envNamespace + "BASE_URL" EnvBaseURL = envNamespace + "BASE_URL"
EnvNameserver = envNamespace + "NAMESERVER"
EnvTTL = envNamespace + "TTL" EnvTTL = envNamespace + "TTL"
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT" EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
@ -46,7 +45,6 @@ type Config struct {
Username string Username string
Token string Token string
BaseURL string BaseURL string
Nameserver string
TTL int TTL int
PropagationTimeout time.Duration PropagationTimeout time.Duration
PollingInterval time.Duration PollingInterval time.Duration
@ -58,7 +56,7 @@ func NewDefaultConfig() *Config {
return &Config{ return &Config{
Mode: env.GetOrDefaultString(EnvMode, "cpanel"), Mode: env.GetOrDefaultString(EnvMode, "cpanel"),
TTL: env.GetOrDefaultInt(EnvTTL, 300), TTL: env.GetOrDefaultInt(EnvTTL, 300),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, dns01.DefaultPropagationTimeout), PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval), PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
HTTPClient: &http.Client{ HTTPClient: &http.Client{
Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second), Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
@ -70,14 +68,13 @@ func NewDefaultConfig() *Config {
type DNSProvider struct { type DNSProvider struct {
config *Config config *Config
client apiClient client apiClient
dnsClient *shared.DNSClient
} }
// NewDNSProvider returns a DNSProvider instance configured for CPanel. // NewDNSProvider returns a DNSProvider instance configured for CPanel.
// Credentials must be passed in the environment variables: // Credentials must be passed in the environment variables:
// CPANEL_USERNAME, CPANEL_TOKEN, CPANEL_BASE_URL, CPANEL_NAMESERVER. // CPANEL_USERNAME, CPANEL_TOKEN, CPANEL_BASE_URL, CPANEL_NAMESERVER.
func NewDNSProvider() (*DNSProvider, error) { func NewDNSProvider() (*DNSProvider, error) {
values, err := env.Get(EnvUsername, EnvToken, EnvBaseURL, EnvNameserver) values, err := env.Get(EnvUsername, EnvToken, EnvBaseURL)
if err != nil { if err != nil {
return nil, fmt.Errorf("cpanel: %w", err) return nil, fmt.Errorf("cpanel: %w", err)
} }
@ -86,7 +83,6 @@ func NewDNSProvider() (*DNSProvider, error) {
config.Username = values[EnvUsername] config.Username = values[EnvUsername]
config.Token = values[EnvToken] config.Token = values[EnvToken]
config.BaseURL = values[EnvBaseURL] config.BaseURL = values[EnvBaseURL]
config.Nameserver = values[EnvNameserver]
return NewDNSProviderConfig(config) return NewDNSProviderConfig(config)
} }
@ -101,7 +97,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("cpanel: some credentials information are missing") 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") return nil, errors.New("cpanel: server information are missing")
} }
@ -113,7 +109,6 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return &DNSProvider{ return &DNSProvider{
config: config, config: config,
client: client, client: client,
dnsClient: shared.NewDNSClient(10 * time.Second),
}, nil }, nil
} }
@ -128,21 +123,19 @@ func (d *DNSProvider) Present(domain, _, keyAuth string) error {
ctx := context.Background() ctx := context.Background()
info := dns01.GetChallengeInfo(domain, keyAuth) info := dns01.GetChallengeInfo(domain, keyAuth)
effectiveDomain := strings.TrimPrefix(info.EffectiveFQDN, "_acme-challenge.") authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
soa, err := d.dnsClient.SOACall(effectiveDomain, d.config.Nameserver)
if err != nil { 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) zoneInfo, err := d.client.FetchZoneInformation(ctx, zone)
if err != nil { if err != nil {
return fmt.Errorf("cpanel[mode=%s]: fetch zone information: %w", d.config.Mode, err) 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 { if err != nil {
return fmt.Errorf("cpanel[mode=%s]: get zone serial: %w", d.config.Mode, err) 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() ctx := context.Background()
info := dns01.GetChallengeInfo(domain, keyAuth) 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 { 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) zoneInfo, err := d.client.FetchZoneInformation(ctx, zone)
if err != nil { if err != nil {
return fmt.Errorf("cpanel[mode=%s]: fetch zone information: %w", d.config.Mode, err) 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 { if err != nil {
return fmt.Errorf("cpanel[mode=%s]: get zone serial: %w", d.config.Mode, err) return fmt.Errorf("cpanel[mode=%s]: get zone serial: %w", d.config.Mode, err)
} }

View file

@ -10,7 +10,6 @@ Example = '''
CPANEL_USERNAME = "yyyy" CPANEL_USERNAME = "yyyy"
CPANEL_TOKEN = "xxxx" CPANEL_TOKEN = "xxxx"
CPANEL_BASE_URL = "https://example.com:2083" \ 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 lego --email you@example.com --dns cpanel --domains my.example.org run
## WHM ## WHM
@ -19,7 +18,6 @@ CPANEL_MODE = whm
CPANEL_USERNAME = "yyyy" CPANEL_USERNAME = "yyyy"
CPANEL_TOKEN = "xxxx" CPANEL_TOKEN = "xxxx"
CPANEL_BASE_URL = "https://example.com:2087" \ 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 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_USERNAME = "username"
CPANEL_TOKEN = "API token" CPANEL_TOKEN = "API token"
CPANEL_BASE_URL = "API server URL" CPANEL_BASE_URL = "API server URL"
CPANEL_NAMESERVER = "Nameserver"
[Configuration.Additional] [Configuration.Additional]
CPANEL_MODE = "use cpanel API or WHM API (Default: cpanel)" CPANEL_MODE = "use cpanel API or WHM API (Default: cpanel)"
CPANEL_POLLING_INTERVAL = "Time between DNS propagation check" CPANEL_POLLING_INTERVAL = "Time between DNS propagation check"

View file

@ -16,8 +16,7 @@ var envTest = tester.NewEnvTest(
EnvMode, EnvMode,
EnvUsername, EnvUsername,
EnvToken, EnvToken,
EnvBaseURL, EnvBaseURL).
EnvNameserver).
WithDomain(envDomain) WithDomain(envDomain)
func TestNewDNSProvider(t *testing.T) { func TestNewDNSProvider(t *testing.T) {
@ -33,7 +32,6 @@ func TestNewDNSProvider(t *testing.T) {
EnvUsername: "user", EnvUsername: "user",
EnvToken: "secret", EnvToken: "secret",
EnvBaseURL: "https://example.com", EnvBaseURL: "https://example.com",
EnvNameserver: "ns.example.com:53",
}, },
expectedMode: "cpanel", expectedMode: "cpanel",
}, },
@ -44,7 +42,6 @@ func TestNewDNSProvider(t *testing.T) {
EnvUsername: "user", EnvUsername: "user",
EnvToken: "secret", EnvToken: "secret",
EnvBaseURL: "https://example.com", EnvBaseURL: "https://example.com",
EnvNameserver: "ns.example.com:53",
}, },
expectedMode: "whm", expectedMode: "whm",
}, },
@ -53,7 +50,6 @@ func TestNewDNSProvider(t *testing.T) {
envVars: map[string]string{ envVars: map[string]string{
EnvToken: "secret", EnvToken: "secret",
EnvBaseURL: "https://example.com", EnvBaseURL: "https://example.com",
EnvNameserver: "ns.example.com:53",
}, },
expected: "cpanel: some credentials information are missing: CPANEL_USERNAME", expected: "cpanel: some credentials information are missing: CPANEL_USERNAME",
}, },
@ -62,7 +58,6 @@ func TestNewDNSProvider(t *testing.T) {
envVars: map[string]string{ envVars: map[string]string{
EnvUsername: "user", EnvUsername: "user",
EnvBaseURL: "https://example.com", EnvBaseURL: "https://example.com",
EnvNameserver: "ns.example.com:53",
}, },
expected: "cpanel: some credentials information are missing: CPANEL_TOKEN", expected: "cpanel: some credentials information are missing: CPANEL_TOKEN",
}, },
@ -72,20 +67,9 @@ func TestNewDNSProvider(t *testing.T) {
EnvUsername: "user", EnvUsername: "user",
EnvToken: "secret", EnvToken: "secret",
EnvBaseURL: "", EnvBaseURL: "",
EnvNameserver: "ns.example.com:53",
}, },
expected: "cpanel: some credentials information are missing: CPANEL_BASE_URL", 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 { for _, test := range testCases {
@ -116,7 +100,6 @@ func TestNewDNSProviderConfig(t *testing.T) {
username string username string
token string token string
baseURL string baseURL string
nameserver string
expected string expected string
}{ }{
{ {
@ -125,14 +108,12 @@ func TestNewDNSProviderConfig(t *testing.T) {
username: "user", username: "user",
token: "secret", token: "secret",
baseURL: "https://example.com", baseURL: "https://example.com",
nameserver: "ns.example.com:53",
}, },
{ {
desc: "missing mode", desc: "missing mode",
username: "user", username: "user",
token: "secret", token: "secret",
baseURL: "https://example.com", baseURL: "https://example.com",
nameserver: "ns.example.com:53",
expected: `cpanel: create client error: unsupported mode: ""`, expected: `cpanel: create client error: unsupported mode: ""`,
}, },
{ {
@ -141,7 +122,6 @@ func TestNewDNSProviderConfig(t *testing.T) {
username: "user", username: "user",
token: "secret", token: "secret",
baseURL: "https://example.com", baseURL: "https://example.com",
nameserver: "ns.example.com:53",
expected: `cpanel: create client error: unsupported mode: "test"`, expected: `cpanel: create client error: unsupported mode: "test"`,
}, },
{ {
@ -150,7 +130,6 @@ func TestNewDNSProviderConfig(t *testing.T) {
username: "", username: "",
token: "secret", token: "secret",
baseURL: "https://example.com", baseURL: "https://example.com",
nameserver: "ns.example.com:53",
expected: "cpanel: some credentials information are missing", expected: "cpanel: some credentials information are missing",
}, },
{ {
@ -159,7 +138,6 @@ func TestNewDNSProviderConfig(t *testing.T) {
username: "user", username: "user",
token: "", token: "",
baseURL: "https://example.com", baseURL: "https://example.com",
nameserver: "ns.example.com:53",
expected: "cpanel: some credentials information are missing", expected: "cpanel: some credentials information are missing",
}, },
{ {
@ -168,16 +146,6 @@ func TestNewDNSProviderConfig(t *testing.T) {
username: "user", username: "user",
token: "secret", token: "secret",
baseURL: "", 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", expected: "cpanel: server information are missing",
}, },
} }
@ -189,7 +157,6 @@ func TestNewDNSProviderConfig(t *testing.T) {
config.Username = test.username config.Username = test.username
config.Token = test.token config.Token = test.token
config.BaseURL = test.baseURL config.BaseURL = test.baseURL
config.Nameserver = test.nameserver
p, err := NewDNSProviderConfig(config) p, err := NewDNSProviderConfig(config)

View file

@ -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
}