cpanel: remove custom DNS call (#2102)
This commit is contained in:
parent
83ff393131
commit
c5a95c4cd0
6 changed files with 74 additions and 188 deletions
|
@ -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()
|
||||
|
|
|
@ -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 |
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Reference in a new issue