feat(rfc2136): add support for IPv6 address in nameserver

Signed-off-by: Johan Fleury <jfleury@arcaik.net>
This commit is contained in:
Johan Fleury 2020-03-09 21:43:56 -04:00
parent 51d46e5f76
commit 08db170a36
No known key found for this signature in database
GPG Key ID: 9A230AEA9EC23C15
11 changed files with 119 additions and 18 deletions

View File

@ -326,7 +326,10 @@ spec:
properties:
nameserver:
description: The IP address or hostname of an authoritative
DNS server supporting RFC2136. Required.
DNS server supporting RFC2136 in the form host:port. If
the host is an IPv6 address it must be enclosed in square
brackets (e.g [2001:db8::1]) ; port is optional. This
field is required.
type: string
tsigAlgorithm:
description: 'The TSIG Algorithm configured in the DNS supporting

View File

@ -380,7 +380,10 @@ spec:
properties:
nameserver:
description: The IP address or hostname of an authoritative
DNS server supporting RFC2136. Required.
DNS server supporting RFC2136 in the form host:port.
If the host is an IPv6 address it must be enclosed
in square brackets (e.g [2001:db8::1]) ; port is
optional. This field is required.
type: string
tsigAlgorithm:
description: 'The TSIG Algorithm configured in the

View File

@ -380,7 +380,10 @@ spec:
properties:
nameserver:
description: The IP address or hostname of an authoritative
DNS server supporting RFC2136. Required.
DNS server supporting RFC2136 in the form host:port.
If the host is an IPv6 address it must be enclosed
in square brackets (e.g [2001:db8::1]) ; port is
optional. This field is required.
type: string
tsigAlgorithm:
description: 'The TSIG Algorithm configured in the

View File

@ -1081,7 +1081,10 @@ spec:
properties:
nameserver:
description: The IP address or hostname of an authoritative
DNS server supporting RFC2136. Required.
DNS server supporting RFC2136 in the form host:port. If
the host is an IPv6 address it must be enclosed in square
brackets (e.g [2001:db8::1]) ; port is optional. This
field is required.
type: string
tsigAlgorithm:
description: 'The TSIG Algorithm configured in the DNS supporting
@ -2542,7 +2545,10 @@ spec:
properties:
nameserver:
description: The IP address or hostname of an authoritative
DNS server supporting RFC2136. Required.
DNS server supporting RFC2136 in the form host:port.
If the host is an IPv6 address it must be enclosed
in square brackets (e.g [2001:db8::1]) ; port is
optional. This field is required.
type: string
tsigAlgorithm:
description: 'The TSIG Algorithm configured in the
@ -4295,7 +4301,10 @@ spec:
properties:
nameserver:
description: The IP address or hostname of an authoritative
DNS server supporting RFC2136. Required.
DNS server supporting RFC2136 in the form host:port.
If the host is an IPv6 address it must be enclosed
in square brackets (e.g [2001:db8::1]) ; port is
optional. This field is required.
type: string
tsigAlgorithm:
description: 'The TSIG Algorithm configured in the

View File

@ -355,7 +355,10 @@ type ACMEIssuerDNS01ProviderAcmeDNS struct {
// ACMEIssuerDNS01ProviderRFC2136 is a structure containing the
// configuration for RFC2136 DNS
type ACMEIssuerDNS01ProviderRFC2136 struct {
// The IP address or hostname of an authoritative DNS server supporting RFC2136. Required.
// The IP address or hostname of an authoritative DNS server supporting
// RFC2136 in the form host:port. If the host is an IPv6 address it must be
// enclosed in square brackets (e.g [2001:db8::1]) ; port is optional.
// This field is required.
Nameserver string `json:"nameserver"`
// The name of the secret containing the TSIG value.

View File

@ -355,7 +355,10 @@ type ACMEIssuerDNS01ProviderAcmeDNS struct {
// ACMEIssuerDNS01ProviderRFC2136 is a structure containing the
// configuration for RFC2136 DNS
type ACMEIssuerDNS01ProviderRFC2136 struct {
// The IP address or hostname of an authoritative DNS server supporting RFC2136. Required.
// The IP address or hostname of an authoritative DNS server supporting
// RFC2136 in the form host:port. If the host is an IPv6 address it must be
// enclosed in square brackets (e.g [2001:db8::1]) ; port is optional.
// This field is required.
Nameserver string `json:"nameserver"`
// The name of the secret containing the TSIG value.

View File

@ -314,7 +314,10 @@ type ACMEIssuerDNS01ProviderAcmeDNS struct {
// ACMEIssuerDNS01ProviderRFC2136 is a structure containing the
// configuration for RFC2136 DNS
type ACMEIssuerDNS01ProviderRFC2136 struct {
// The IP address or hostname of an authoritative DNS server supporting RFC2136. Required.
// The IP address or hostname of an authoritative DNS server supporting
// RFC2136 in the form host:port. If the host is an IPv6 address it must be
// enclosed in square brackets (e.g [2001:db8::1]) ; port is optional.
// This field is required.
Nameserver string
// The name of the secret containing the TSIG value.

View File

@ -348,7 +348,7 @@ func ValidateACMEChallengeSolverDNS01(p *cmacme.ACMEChallengeSolverDNS01, fldPat
el = append(el, field.Required(fldPath.Child("rfc2136", "nameserver"), ""))
} else {
if _, err := util.ValidNameserver(p.RFC2136.Nameserver); err != nil {
el = append(el, field.Invalid(fldPath.Child("rfc2136", "nameserver"), p.RFC2136.Nameserver, "nameserver must be an hostname or IP address in the form host[:port]."))
el = append(el, field.Invalid(fldPath.Child("rfc2136", "nameserver"), p.RFC2136.Nameserver, "nameserver must be set in the form host:port where host is an IPv4 address, an enclosed IPv6 address or a hostname and port is an optional port number."))
}
}
if len(p.RFC2136.TSIGAlgorithm) > 0 {

View File

@ -656,6 +656,34 @@ func TestValidateACMEIssuerDNS01Config(t *testing.T) {
},
errs: []*field.Error{},
},
"rfc2136 provider with unenclosed IPv6 nameserver": {
cfg: &cmacme.ACMEChallengeSolverDNS01{
RFC2136: &cmacme.ACMEIssuerDNS01ProviderRFC2136{
Nameserver: "2001:db8::1",
},
},
errs: []*field.Error{
field.Invalid(fldPath.Child("rfc2136", "nameserver"), "2001:db8::1", "nameserver must be set in the form host:port where host is an IPv4 address, an enclosed IPv6 address or a hostname and port is an optional port number."),
},
},
"rfc2136 provider with empty IPv6 nameserver": {
cfg: &cmacme.ACMEChallengeSolverDNS01{
RFC2136: &cmacme.ACMEIssuerDNS01ProviderRFC2136{
Nameserver: "[]:53",
},
},
errs: []*field.Error{
field.Invalid(fldPath.Child("rfc2136", "nameserver"), "[]:53", "nameserver must be set in the form host:port where host is an IPv4 address, an enclosed IPv6 address or a hostname and port is an optional port number."),
},
},
"rfc2136 provider with IPv6 nameserver": {
cfg: &cmacme.ACMEChallengeSolverDNS01{
RFC2136: &cmacme.ACMEIssuerDNS01ProviderRFC2136{
Nameserver: "[2001:db8::1]",
},
},
errs: []*field.Error{},
},
"rfc2136 provider with FQDN nameserver": {
cfg: &cmacme.ACMEChallengeSolverDNS01{
RFC2136: &cmacme.ACMEIssuerDNS01ProviderRFC2136{
@ -679,7 +707,7 @@ func TestValidateACMEIssuerDNS01Config(t *testing.T) {
},
},
errs: []*field.Error{
field.Invalid(fldPath.Child("rfc2136", "nameserver"), ":53", "nameserver must be an hostname or IP address in the form host[:port]."),
field.Invalid(fldPath.Child("rfc2136", "nameserver"), ":53", "nameserver must be set in the form host:port where host is an IPv4 address, an enclosed IPv6 address or a hostname and port is an optional port number."),
},
},
"rfc2136 provider using case-camel in algorithm": {

View File

@ -37,6 +37,9 @@ func ValidNameserver(nameserver string) (string, error) {
// 8.8.8.8 "" "" missing port in address
// 8.8.8.8: "8.8.8.8" "" <nil>
// 8.8.8.8.8:53 "8.8.8.8" 53 <nil>
// [2001:db8::1] "" "" missing port in address
// [2001:db8::1]: "2001:db8::1" "" <nil>
// [2001:db8::1]:53 "2001:db8::1" 53 <nil>
// nameserver.com "" "" missing port in address
// nameserver.com: "nameserver.com" "" <nil>
// nameserver.com:53 "nameserver.com" 53 <nil>
@ -44,19 +47,20 @@ func ValidNameserver(nameserver string) (string, error) {
host, port, err := net.SplitHostPort(nameserver)
if err != nil {
if strings.Contains(err.Error(), "missing port") {
host = nameserver
// net.JoinHostPort expect IPv6 address to be unenclosed
host = strings.Trim(nameserver, "[]")
} else {
return "", fmt.Errorf("RFC2136 nameserver is invalid: %s", err.Error())
}
}
if port == "" {
port = defaultRFC2136Port
}
if host == "" {
return "", fmt.Errorf("RFC2136 nameserver has no host defined, %v", nameserver)
}
nameserver = host + ":" + port
if port == "" {
port = defaultRFC2136Port
}
return nameserver, nil
return net.JoinHostPort(host, port), nil
}

View File

@ -181,6 +181,48 @@ func TestRFC2136NameserverIPv4WithPort(t *testing.T) {
}
}
func TestRFC2136NameserverIPv6NotEnclosed(t *testing.T) {
nameserver := "2001:db8::1"
_, err := NewDNSProviderCredentials(nameserver, "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret)
assert.Error(t, err)
}
func TestRFC2136NameserverIPv6Empty(t *testing.T) {
nameserver := "[]:53"
_, err := NewDNSProviderCredentials(nameserver, "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret)
assert.Error(t, err)
}
func TestRFC2136NameserverIPv6WithoutPort(t *testing.T) {
nameserver := "[2001:db8::1]"
dnsProvider, err := NewDNSProviderCredentials(nameserver, "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret)
assert.NoError(t, err)
if dnsProvider.nameserver != nameserver+":"+defaultPort {
t.Errorf("dnsProvider.nameserver to be %v:%v, but it is %v", nameserver, defaultPort, dnsProvider.nameserver)
}
}
func TestRFC2136NameserverIPv6WithEmptyPort(t *testing.T) {
nameserver := "[2001:db8::1]:"
dnsProvider, err := NewDNSProviderCredentials(nameserver, "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret)
assert.NoError(t, err)
if dnsProvider.nameserver != nameserver+defaultPort {
t.Errorf("dnsProvider.nameserver to be %v%v, but it is %v", nameserver, defaultPort, dnsProvider.nameserver)
}
}
func TestRFC2136NameserverIPv6WithPort(t *testing.T) {
nameserver := "[2001:db8::1]:12345"
dnsProvider, err := NewDNSProviderCredentials(nameserver, "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret)
assert.NoError(t, err)
if dnsProvider.nameserver != nameserver {
t.Errorf("dnsProvider.nameserver to be %v, but it is %v", nameserver, dnsProvider.nameserver)
}
}
func TestRFC2136NameserverFQDNWithoutPort(t *testing.T) {
nameserver := "dns.example.net"
dnsProvider, err := NewDNSProviderCredentials(nameserver, "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret)