1
0
mirror of https://github.com/StackExchange/dnscontrol.git synced 2024-05-11 05:55:12 +00:00

Expect SOA mailbox in hostmaster@example.org format instead of hostmaster.example.org (#2037)

Co-authored-by: Yannik Sembritzki <yannik@sembritzki.org>
Co-authored-by: Tom Limoncelli <tlimoncelli@stackoverflow.com>
This commit is contained in:
Yannik Sembritzki
2023-02-07 19:55:41 +05:30
committed by GitHub
parent 9eacd42b63
commit dc02d5b74f
5 changed files with 64 additions and 10 deletions

View File

@ -24,12 +24,14 @@ parameter_types:
```javascript
D("example.com", REG_THIRDPARTY, DnsProvider("DNS_BIND"),
SOA("@", "ns3.example.org.", "hostmaster.example.org.", 3600, 600, 604800, 1440),
SOA("@", "ns3.example.org.", "hostmaster@example.org", 3600, 600, 604800, 1440),
);
```
## Notes
The email address should be specified like a normal RFC822/RFC5322 address (user@hostname.com). It will be converted into the required format (e.g. BIND format: `user.hostname.com`) by the provider as required. This has the benefit of being more human-readable plus DNSControl can properly handle escaping and other issues.
## Notes
* Previously, the accepted format for the SOA mailbox field was `hostmaster.example.org`. This has been changed to `hostmaster@example.org`
* The serial number is managed automatically. It isn't even a field in `SOA()`.
* Most providers automatically generate SOA records. They will ignore any `SOA()` statements.

11
pkg/soautil/soautil.go Normal file
View File

@ -0,0 +1,11 @@
package soautil
import "strings"
func RFC5322MailToBind(rfc5322Mail string) string {
res := strings.SplitN(rfc5322Mail, "@", 2)
user_part, domain_part := res[0], res[1]
// RFC-1035 [Section-8]
user_part = strings.ReplaceAll(user_part, ".", "\\.")
return user_part + "." + domain_part
}

View File

@ -0,0 +1,28 @@
package soautil
import (
"reflect"
"testing"
)
func Test_RFC5322MailToBind(t *testing.T) {
type args struct {
rfc5322Mail string
}
tests := []struct {
name string
rfc5322Mail string
bindMail string
}{
{"0", "hostmaster@example.com", "hostmaster.example.com"},
{"1", "admin.dns@example.com", "admin\\.dns.example.com"},
{"2", "hostmaster@sub.example.com", "hostmaster.sub.example.com"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := RFC5322MailToBind(tt.rfc5322Mail); !reflect.DeepEqual(got, tt.bindMail) {
t.Errorf("RFC5322MailToBind(%v) = %v, want %v", tt.rfc5322Mail, got, tt.bindMail)
}
})
}
}

View File

@ -1,6 +1,11 @@
package bind
import "github.com/StackExchange/dnscontrol/v3/models"
import (
"fmt"
"github.com/StackExchange/dnscontrol/v3/models"
"github.com/StackExchange/dnscontrol/v3/pkg/soautil"
"strings"
)
func makeSoa(origin string, defSoa *SoaDefaults, existing, desired *models.RecordConfig) (*models.RecordConfig, uint32) {
// Create a SOA record. Take data from desired, existing, default,
@ -19,10 +24,18 @@ func makeSoa(origin string, defSoa *SoaDefaults, existing, desired *models.Recor
desired = &models.RecordConfig{}
}
soaMail := firstNonNull(desired.SoaMbox, existing.SoaMbox, defSoa.Mbox, "DEFAULT_NOT_SET.")
if strings.Contains(soaMail, "@") {
soaMail = soautil.RFC5322MailToBind(soaMail)
} else {
fmt.Println("WARNING: SOA hostmaster address must be in the format hostmaster@example.com")
fmt.Println("WARNING: hostmaster.example.com is deprecated and will be dropped in a future version")
}
soaRec.TTL = firstNonZero(desired.TTL, defSoa.TTL, existing.TTL, models.DefaultTTL)
soaRec.SetTargetSOA(
firstNonNull(desired.GetTargetField(), existing.GetTargetField(), defSoa.Ns, "DEFAULT_NOT_SET."),
firstNonNull(desired.SoaMbox, existing.SoaMbox, defSoa.Mbox, "DEFAULT_NOT_SET."),
soaMail,
firstNonZero(desired.SoaSerial, existing.SoaSerial, defSoa.Serial, 1),
firstNonZero(desired.SoaRefresh, existing.SoaRefresh, defSoa.Refresh, 3600),
firstNonZero(desired.SoaRetry, existing.SoaRetry, defSoa.Retry, 600),

View File

@ -32,7 +32,7 @@ func Test_makeSoa(t *testing.T) {
},
{
// If everything is filled, leave the desired values in place.
&SoaDefaults{"ns.example.com", "root.example.com", 1, 2, 3, 4, 5, models.DefaultTTL},
&SoaDefaults{"ns.example.com", "root@example.com", 1, 2, 3, 4, 5, models.DefaultTTL},
mkRC("a", &models.RecordConfig{SoaMbox: "aa", SoaSerial: 10, SoaRefresh: 11, SoaRetry: 12, SoaExpire: 13, SoaMinttl: 14}),
mkRC("b", &models.RecordConfig{SoaMbox: "bb", SoaSerial: 15, SoaRefresh: 16, SoaRetry: 17, SoaExpire: 18, SoaMinttl: 19}),
mkRC("b", &models.RecordConfig{SoaMbox: "bb", SoaSerial: 15, SoaRefresh: 16, SoaRetry: 17, SoaExpire: 18, SoaMinttl: 19}),
@ -40,7 +40,7 @@ func Test_makeSoa(t *testing.T) {
},
{
// Test incrementing serial.
&SoaDefaults{"ns.example.com", "root.example.com", 1, 2, 3, 4, 5, models.DefaultTTL},
&SoaDefaults{"ns.example.com", "root@example.com", 1, 2, 3, 4, 5, models.DefaultTTL},
mkRC("a", &models.RecordConfig{SoaMbox: "aa", SoaSerial: 2019022301, SoaRefresh: 11, SoaRetry: 12, SoaExpire: 13, SoaMinttl: 14}),
mkRC("b", &models.RecordConfig{SoaMbox: "bb", SoaSerial: 0, SoaRefresh: 16, SoaRetry: 17, SoaExpire: 18, SoaMinttl: 19}),
mkRC("b", &models.RecordConfig{SoaMbox: "bb", SoaSerial: 2019022301, SoaRefresh: 16, SoaRetry: 17, SoaExpire: 18, SoaMinttl: 19}),
@ -48,7 +48,7 @@ func Test_makeSoa(t *testing.T) {
},
{
// Test incrementing serial_2.
&SoaDefaults{"ns.example.com", "root.example.com", 1, 2, 3, 4, 5, models.DefaultTTL},
&SoaDefaults{"ns.example.com", "root@example.com", 1, 2, 3, 4, 5, models.DefaultTTL},
mkRC("a", &models.RecordConfig{SoaMbox: "aa", SoaSerial: 0, SoaRefresh: 11, SoaRetry: 12, SoaExpire: 13, SoaMinttl: 14}),
mkRC("b", &models.RecordConfig{SoaMbox: "bb", SoaSerial: 2019022304, SoaRefresh: 16, SoaRetry: 17, SoaExpire: 18, SoaMinttl: 19}),
mkRC("b", &models.RecordConfig{SoaMbox: "bb", SoaSerial: 2019022304, SoaRefresh: 16, SoaRetry: 17, SoaExpire: 18, SoaMinttl: 19}),
@ -56,7 +56,7 @@ func Test_makeSoa(t *testing.T) {
},
{
// If there are gaps in existing or desired, fill in as appropriate.
&SoaDefaults{"ns.example.com", "root.example.com", 1, 2, 3, 4, 5, models.DefaultTTL},
&SoaDefaults{"ns.example.com", "root@example.com", 1, 2, 3, 4, 5, models.DefaultTTL},
mkRC("", &models.RecordConfig{SoaMbox: "aa", SoaSerial: 0, SoaRefresh: 11, SoaRetry: 0, SoaExpire: 13, SoaMinttl: 0}),
mkRC("b", &models.RecordConfig{SoaMbox: "", SoaSerial: 15, SoaRefresh: 0, SoaRetry: 17, SoaExpire: 0, SoaMinttl: 19}),
mkRC("b", &models.RecordConfig{SoaMbox: "aa", SoaSerial: 15, SoaRefresh: 11, SoaRetry: 17, SoaExpire: 13, SoaMinttl: 19}),
@ -64,7 +64,7 @@ func Test_makeSoa(t *testing.T) {
},
{
// Gaps + existing==nil
&SoaDefaults{"ns.example.com", "root.example.com", 1, 2, 3, 4, 5, models.DefaultTTL},
&SoaDefaults{"ns.example.com", "root@example.com", 1, 2, 3, 4, 5, models.DefaultTTL},
nil,
mkRC("b", &models.RecordConfig{SoaMbox: "", SoaSerial: 15, SoaRefresh: 0, SoaRetry: 17, SoaExpire: 0, SoaMinttl: 19}),
mkRC("b", &models.RecordConfig{SoaMbox: "root.example.com", SoaSerial: 15, SoaRefresh: 2, SoaRetry: 17, SoaExpire: 4, SoaMinttl: 19}),
@ -73,7 +73,7 @@ func Test_makeSoa(t *testing.T) {
{
// Gaps + desired==nil
// NB(tom): In the code as of 2020-02-23, desired will never be nil.
&SoaDefaults{"ns.example.com", "root.example.com", 1, 2, 3, 4, 5, models.DefaultTTL},
&SoaDefaults{"ns.example.com", "root@example.com", 1, 2, 3, 4, 5, models.DefaultTTL},
mkRC("", &models.RecordConfig{SoaMbox: "aa", SoaSerial: 0, SoaRefresh: 11, SoaRetry: 0, SoaExpire: 13, SoaMinttl: 0}),
nil,
mkRC("ns.example.com", &models.RecordConfig{SoaMbox: "aa", SoaSerial: 1, SoaRefresh: 11, SoaRetry: 3, SoaExpire: 13, SoaMinttl: 5}),