2023-12-24 10:18:08 +00:00
// This file is part of the happyDomain (R) project.
// Copyright (c) 2020-2024 happyDomain
// Authors: Pierre-Olivier Mercier, et al.
2020-05-09 11:14:29 +00:00
//
2023-12-24 10:18:08 +00:00
// This program is offered under a commercial and under the AGPL license.
// For commercial licensing, contact us at <contact@happydomain.org>.
2020-05-09 11:14:29 +00:00
//
2023-12-24 10:18:08 +00:00
// For AGPL licensing:
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
2020-05-09 11:14:29 +00:00
//
2023-12-24 10:18:08 +00:00
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
2020-05-09 11:14:29 +00:00
//
2023-12-24 10:18:08 +00:00
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2020-05-09 11:14:29 +00:00
2020-10-10 16:44:17 +00:00
package abstract
2020-05-09 11:14:29 +00:00
import (
2020-05-10 09:23:55 +00:00
"fmt"
"strings"
2020-05-10 22:14:31 +00:00
"time"
2020-05-10 09:23:55 +00:00
2023-09-15 18:25:31 +00:00
"github.com/StackExchange/dnscontrol/v4/models"
2020-05-09 11:14:29 +00:00
"github.com/miekg/dns"
2023-09-07 09:37:18 +00:00
"git.happydns.org/happyDomain/model"
"git.happydns.org/happyDomain/services"
"git.happydns.org/happyDomain/services/common"
"git.happydns.org/happyDomain/utils"
2020-05-09 11:14:29 +00:00
)
2023-12-06 00:56:51 +00:00
type NSOnlyOrigin struct {
NameServers [ ] string ` json:"ns" happydomain:"label=Zone's Name Servers" `
}
func ( s * NSOnlyOrigin ) GetNbResources ( ) int {
return len ( s . NameServers )
}
func ( s * NSOnlyOrigin ) GenComment ( origin string ) string {
return fmt . Sprintf ( "%d NS" , len ( s . NameServers ) )
}
func ( s * NSOnlyOrigin ) GenRRs ( domain string , ttl uint32 , origin string ) ( rrs models . Records ) {
for _ , ns := range s . NameServers {
rc := utils . NewRecordConfig ( domain , "NS" , ttl , origin )
rc . SetTarget ( utils . DomainFQDN ( ns , origin ) )
rrs = append ( rrs , rc )
}
return
}
2020-05-09 11:14:29 +00:00
type Origin struct {
2023-02-24 15:49:32 +00:00
Ns string ` json:"mname" happydomain:"label=Name Server,placeholder=ns0,required,description=The domain name of the name server that was the original or primary source of data for this zone." `
2023-12-06 00:56:51 +00:00
Mbox string ` json:"rname" happydomain:"label=Contact Email,placeholder=dnsmaster,required,description=A <domain-name> which specifies the mailbox of the person responsible for this zone." `
2023-02-24 15:49:32 +00:00
Serial uint32 ` json:"serial" happydomain:"label=Zone Serial,required,description=The unsigned 32 bit version number of the original copy of the zone. Zone transfers preserve this value. This value wraps and should be compared using sequence space arithmetic." `
2023-02-23 01:20:52 +00:00
Refresh common . Duration ` json:"refresh" happydomain:"label=Slave Refresh Time,required,description=The time interval before the zone should be refreshed by name servers other than the primary." `
Retry common . Duration ` json:"retry" happydomain:"label=Retry Interval on failed refresh,required,description=The time interval that should elapse before a failed refresh should be retried by a slave name server." `
2023-02-24 15:49:32 +00:00
Expire common . Duration ` json:"expire" happydomain:"label=Authoritative Expiry,required,description=Time value that specifies the upper limit on the time interval that can elapse before the zone is no longer authoritative." `
Negttl common . Duration ` json:"nxttl" happydomain:"label=Negative Caching Time,required,description=Maximal time a resolver should cache a negative authoritative answer (such as NXDOMAIN ...)." `
NameServers [ ] string ` json:"ns" happydomain:"label=Zone's Name Servers" `
2020-05-09 11:14:29 +00:00
}
2020-05-10 09:23:55 +00:00
func ( s * Origin ) GetNbResources ( ) int {
2023-12-06 00:56:51 +00:00
if s . Ns == "" {
return len ( s . NameServers )
} else {
return len ( s . NameServers ) + 1
}
2020-05-10 09:23:55 +00:00
}
2020-05-09 11:14:29 +00:00
2020-05-10 09:23:55 +00:00
func ( s * Origin ) GenComment ( origin string ) string {
2023-12-06 00:56:51 +00:00
if s . Ns == "" {
return fmt . Sprintf ( "%d NS" , len ( s . NameServers ) )
}
2020-06-27 13:14:52 +00:00
ns := ""
if s . NameServers != nil {
ns = fmt . Sprintf ( " + %d NS" , len ( s . NameServers ) )
}
return fmt . Sprintf ( "%s %s %d" + ns , strings . TrimSuffix ( s . Ns , "." + origin ) , strings . TrimSuffix ( s . Mbox , "." + origin ) , s . Serial )
2020-05-10 09:23:55 +00:00
}
2023-09-15 18:25:31 +00:00
func ( s * Origin ) GenRRs ( domain string , ttl uint32 , origin string ) ( rrs models . Records ) {
2023-12-06 00:56:51 +00:00
if s . Ns != "" {
rc := utils . NewRecordConfig ( domain , "SOA" , ttl , origin )
rc . SoaMbox = utils . DomainFQDN ( s . Mbox , origin )
rc . SoaSerial = s . Serial
rc . SoaRefresh = uint32 ( s . Refresh . Seconds ( ) )
rc . SoaRetry = uint32 ( s . Retry . Seconds ( ) )
rc . SoaExpire = uint32 ( s . Expire . Seconds ( ) )
rc . SoaMinttl = uint32 ( s . Negttl . Seconds ( ) )
rc . SetTarget ( utils . DomainFQDN ( s . Ns , origin ) )
rrs = append ( rrs , rc )
}
2020-06-27 13:14:52 +00:00
for _ , ns := range s . NameServers {
2023-12-06 00:56:51 +00:00
rc := utils . NewRecordConfig ( domain , "NS" , ttl , origin )
2023-09-15 18:25:31 +00:00
rc . SetTarget ( utils . DomainFQDN ( ns , origin ) )
rrs = append ( rrs , rc )
2020-06-27 13:14:52 +00:00
}
2020-05-09 11:14:29 +00:00
return
}
2020-10-10 16:44:17 +00:00
func origin_analyze ( a * svcs . Analyzer ) error {
2023-12-06 00:56:51 +00:00
hasSOA := false
2020-10-10 16:44:17 +00:00
for _ , record := range a . SearchRR ( svcs . AnalyzerRecordFilter { Type : dns . TypeSOA } ) {
2023-09-15 18:25:31 +00:00
if record . Type == "SOA" {
2023-12-06 00:56:51 +00:00
hasSOA = true
2020-06-27 13:14:52 +00:00
origin := & Origin {
2023-09-15 18:25:31 +00:00
Ns : record . GetTargetField ( ) ,
Mbox : record . SoaMbox ,
Serial : record . SoaSerial ,
Refresh : common . Duration ( time . Duration ( record . SoaRefresh ) * time . Second ) ,
Retry : common . Duration ( time . Duration ( record . SoaRetry ) * time . Second ) ,
Expire : common . Duration ( time . Duration ( record . SoaExpire ) * time . Second ) ,
Negttl : common . Duration ( time . Duration ( record . SoaMinttl ) * time . Second ) ,
2020-06-27 13:14:52 +00:00
}
2020-10-06 14:45:41 +00:00
a . UseRR (
2020-05-10 09:23:55 +00:00
record ,
2023-09-15 18:25:31 +00:00
record . NameFQDN ,
2020-06-27 13:14:52 +00:00
origin ,
2020-05-10 09:23:55 +00:00
)
2020-06-27 13:14:52 +00:00
2023-09-15 18:25:31 +00:00
for _ , record := range a . SearchRR ( svcs . AnalyzerRecordFilter { Type : dns . TypeNS , Domain : record . NameFQDN } ) {
if record . Type == "NS" {
origin . NameServers = append ( origin . NameServers , record . GetTargetField ( ) )
2020-10-06 14:45:41 +00:00
a . UseRR (
2020-06-27 13:14:52 +00:00
record ,
2023-09-15 18:25:31 +00:00
record . NameFQDN ,
2020-06-27 13:14:52 +00:00
origin ,
)
}
}
2020-05-10 09:23:55 +00:00
}
}
2023-12-06 00:56:51 +00:00
if ! hasSOA {
origin := & NSOnlyOrigin { }
for _ , record := range a . SearchRR ( svcs . AnalyzerRecordFilter { Type : dns . TypeNS , Domain : a . GetOrigin ( ) } ) {
if record . Type == "NS" {
origin . NameServers = append ( origin . NameServers , record . GetTargetField ( ) )
a . UseRR (
record ,
record . NameFQDN ,
origin ,
)
}
}
}
2020-05-09 11:14:29 +00:00
return nil
}
func init ( ) {
2020-10-10 16:44:17 +00:00
svcs . RegisterService (
2020-05-09 11:14:29 +00:00
func ( ) happydns . Service {
return & Origin { }
} ,
origin_analyze ,
2020-10-10 16:44:17 +00:00
svcs . ServiceInfos {
2020-05-09 11:14:29 +00:00
Name : "Origin" ,
2020-07-05 19:39:17 +00:00
Description : "This is the root of your domain." ,
2020-10-10 16:44:17 +00:00
Family : svcs . Abstract ,
2020-05-09 11:14:29 +00:00
Categories : [ ] string {
"internal" ,
} ,
2023-02-23 01:20:52 +00:00
RecordTypes : [ ] uint16 {
dns . TypeSOA ,
dns . TypeNS ,
} ,
2020-10-10 16:44:17 +00:00
Restrictions : svcs . ServiceRestrictions {
2020-07-06 09:07:37 +00:00
RootOnly : true ,
Single : true ,
2020-07-26 18:54:53 +00:00
NeedTypes : [ ] uint16 {
dns . TypeSOA ,
} ,
2020-07-06 09:07:37 +00:00
} ,
2020-05-09 11:14:29 +00:00
} ,
2020-05-10 22:13:16 +00:00
0 ,
2020-05-09 11:14:29 +00:00
)
2023-12-06 00:56:51 +00:00
svcs . RegisterService (
func ( ) happydns . Service {
return & NSOnlyOrigin { }
} ,
nil ,
svcs . ServiceInfos {
Name : "Origin" ,
Description : "This is the root of your domain." ,
Family : svcs . Hidden ,
Categories : [ ] string {
"internal" ,
} ,
RecordTypes : [ ] uint16 {
dns . TypeNS ,
} ,
Restrictions : svcs . ServiceRestrictions {
RootOnly : true ,
Single : true ,
NeedTypes : [ ] uint16 {
dns . TypeNS ,
} ,
} ,
} ,
0 ,
)
2020-05-09 11:14:29 +00:00
}