2014-11-26 02:59:18 +00:00
package ncdomain
import "encoding/json"
import "net"
import "fmt"
import "github.com/miekg/dns"
import "encoding/base64"
import "encoding/hex"
2017-06-07 04:14:50 +00:00
import "github.com/namecoin/ncdns/util"
2014-12-01 00:44:06 +00:00
import "strings"
2014-12-12 11:23:00 +00:00
import "strconv"
2014-11-26 02:59:18 +00:00
2015-11-12 05:18:02 +00:00
import "github.com/namecoin/ncdns/x509"
import "github.com/namecoin/ncdns/certdehydrate"
2014-11-26 02:59:18 +00:00
const depthLimit = 16
const mergeDepthLimit = 4
2014-12-04 12:04:14 +00:00
const defaultTTL = 600
2014-11-26 02:59:18 +00:00
2014-12-01 00:44:06 +00:00
// Note: Name values in Value (e.g. those in Alias and Target, Services, MXs,
// etc.) are not necessarily fully qualified and must be fully qualified before
// being used. Non-fully-qualified names are relative to the name apex, and
// should be qualified as such based on whatever the corresponding name for the
// Value is and the zone apex you are using for .bit. These assumptions are not
// built-in for you to give flexibility in where the .bit zone is mounted,
// DNS namespace-wise. If you just call RRs() or RRsRecursive() you don't have
// to worry about any of this.
//
// Because empty values are used to indicate the non-presence of an option
// in some cases, namely for Alias and Translate, the empty string is represented as "=".
// Therefore when qualifying names in a Value yourself you must check if the
// input string is "=" and if so, replace it with "" first.
2014-11-26 02:59:18 +00:00
type Value struct {
2014-12-01 00:44:06 +00:00
IP [ ] net . IP
IP6 [ ] net . IP
NS [ ] string
Alias string
HasAlias bool // True if Alias was specified. Necessary as "" is a valid relative alias.
Translate string
HasTranslate bool // True if Translate was specified. Necessary as "" is a valid relative value for Translate.
DS [ ] * dns . DS
TXT [ ] [ ] string
2015-05-22 13:18:57 +00:00
SRV [ ] * dns . SRV
Hostmaster string // "hostmaster@example.com"
MX [ ] * dns . MX // header name is left blank
TLSA [ ] * dns . TLSA
2015-11-12 05:18:02 +00:00
TLSAGenerated [ ] x509 . Certificate // Certs can be dehydrated in the blockchain, they will be put here without SAN values. SAN must be filled in before use.
2014-12-01 00:44:06 +00:00
Map map [ string ] * Value // may contain and "*", will not contain ""
// set if the value is at the top level (alas necessary for relname interpretation)
IsTopLevel bool
}
2014-12-06 09:30:14 +00:00
func ( v * Value ) mkString ( i string ) string {
s := i [ 1 : ] + "Value:"
i += " "
if v . HasAlias {
s += i + "CNAME: \"" + v . Alias + "\""
}
if v . HasTranslate {
s += i + "DNAME: \"" + v . Translate + "\""
}
if v . Hostmaster != "" {
s += i + "Hostmaster: " + v . Hostmaster
}
for _ , ip := range v . IP {
s += i + "IPv4 Address: " + ip . String ( )
}
for _ , ip := range v . IP6 {
s += i + "IPv6 Address: " + ip . String ( )
}
for _ , ns := range v . NS {
s += i + "Nameserver: " + ns
}
for _ , ds := range v . DS {
s += i + "DS Record: " + ds . String ( )
}
for _ , txt := range v . TXT {
s += i + "TXT Record:"
for _ , txtc := range txt {
s += i + " " + txtc
}
}
2015-05-22 13:18:57 +00:00
for _ , srv := range v . SRV {
2014-12-06 09:30:14 +00:00
s += i + "SRV Record: " + srv . String ( )
}
for _ , tlsa := range v . TLSA {
s += i + "TLSA Record: " + tlsa . String ( )
}
if len ( v . Map ) > 0 {
s += i + "Subdomains:"
for k , v := range v . Map {
s += i + " " + k + ":"
s += v . mkString ( i + " " )
}
}
return s
}
func ( v * Value ) String ( ) string {
return v . mkString ( "\n" )
}
2014-12-01 00:44:06 +00:00
func ( v * Value ) RRs ( out [ ] dns . RR , suffix , apexSuffix string ) ( [ ] dns . RR , error ) {
2014-11-26 02:59:18 +00:00
il := len ( out )
suffix = dns . Fqdn ( suffix )
2014-12-01 00:44:06 +00:00
apexSuffix = dns . Fqdn ( apexSuffix )
2014-11-26 02:59:18 +00:00
2014-12-01 00:44:06 +00:00
out , _ = v . appendNSs ( out , suffix , apexSuffix )
2014-11-27 20:36:21 +00:00
if len ( v . NS ) == 0 {
2014-12-01 00:44:06 +00:00
out , _ = v . appendTranslate ( out , suffix , apexSuffix )
if ! v . HasTranslate {
out , _ = v . appendAlias ( out , suffix , apexSuffix )
if ! v . HasAlias {
out , _ = v . appendIPs ( out , suffix , apexSuffix )
out , _ = v . appendIP6s ( out , suffix , apexSuffix )
out , _ = v . appendTXTs ( out , suffix , apexSuffix )
out , _ = v . appendMXs ( out , suffix , apexSuffix )
2015-05-22 13:18:57 +00:00
out , _ = v . appendSRVs ( out , suffix , apexSuffix )
out , _ = v . appendTLSA ( out , suffix , apexSuffix )
2014-11-27 20:36:21 +00:00
}
}
}
2014-12-01 00:44:06 +00:00
out , _ = v . appendDSs ( out , suffix , apexSuffix )
2014-11-26 02:59:18 +00:00
xout := out [ il : ]
for i := range xout {
2014-11-27 20:36:21 +00:00
h := xout [ i ] . Header ( )
2014-12-01 00:44:06 +00:00
if rrtypeHasPrefix ( h . Rrtype ) {
2014-12-12 11:23:00 +00:00
h . Name += suffix
2014-11-27 20:36:21 +00:00
} else {
h . Name = suffix
}
2014-11-26 02:59:18 +00:00
}
return out , nil
}
2014-12-01 00:44:06 +00:00
func rrtypeHasPrefix ( t uint16 ) bool {
return t == dns . TypeSRV || t == dns . TypeTLSA
}
func ( v * Value ) appendIPs ( out [ ] dns . RR , suffix , apexSuffix string ) ( [ ] dns . RR , error ) {
2014-11-26 02:59:18 +00:00
for _ , ip := range v . IP {
out = append ( out , & dns . A {
Hdr : dns . RR_Header {
Name : suffix ,
Rrtype : dns . TypeA ,
Class : dns . ClassINET ,
2014-12-04 12:04:14 +00:00
Ttl : defaultTTL ,
2014-11-26 02:59:18 +00:00
} ,
A : ip ,
} )
}
return out , nil
}
2014-12-01 00:44:06 +00:00
func ( v * Value ) appendIP6s ( out [ ] dns . RR , suffix , apexSuffix string ) ( [ ] dns . RR , error ) {
2014-11-26 02:59:18 +00:00
for _ , ip := range v . IP6 {
out = append ( out , & dns . AAAA {
Hdr : dns . RR_Header {
Name : suffix ,
Rrtype : dns . TypeAAAA ,
Class : dns . ClassINET ,
2014-12-04 12:04:14 +00:00
Ttl : defaultTTL ,
2014-11-26 02:59:18 +00:00
} ,
AAAA : ip ,
} )
}
return out , nil
}
2014-12-01 00:44:06 +00:00
func ( v * Value ) appendNSs ( out [ ] dns . RR , suffix , apexSuffix string ) ( [ ] dns . RR , error ) {
2014-11-26 02:59:18 +00:00
for _ , ns := range v . NS {
2014-12-01 00:44:06 +00:00
qn , ok := v . qualify ( ns , suffix , apexSuffix )
if ! ok {
continue
}
2014-11-26 02:59:18 +00:00
out = append ( out , & dns . NS {
Hdr : dns . RR_Header {
Name : suffix ,
Rrtype : dns . TypeNS ,
Class : dns . ClassINET ,
2014-12-04 12:04:14 +00:00
Ttl : defaultTTL ,
2014-11-26 02:59:18 +00:00
} ,
2014-12-01 00:44:06 +00:00
Ns : qn ,
2014-11-26 02:59:18 +00:00
} )
}
return out , nil
}
2014-12-01 00:44:06 +00:00
func ( v * Value ) appendTXTs ( out [ ] dns . RR , suffix , apexSuffix string ) ( [ ] dns . RR , error ) {
2014-11-26 02:59:18 +00:00
for _ , txt := range v . TXT {
out = append ( out , & dns . TXT {
Hdr : dns . RR_Header {
Name : suffix ,
Rrtype : dns . TypeTXT ,
Class : dns . ClassINET ,
2014-12-04 12:04:14 +00:00
Ttl : defaultTTL ,
2014-11-26 02:59:18 +00:00
} ,
Txt : txt ,
} )
}
return out , nil
}
2014-12-01 00:44:06 +00:00
func ( v * Value ) appendDSs ( out [ ] dns . RR , suffix , apexSuffix string ) ( [ ] dns . RR , error ) {
2014-11-26 02:59:18 +00:00
for _ , ds := range v . DS {
out = append ( out , ds )
}
return out , nil
}
2014-12-01 00:44:06 +00:00
func ( v * Value ) appendMXs ( out [ ] dns . RR , suffix , apexSuffix string ) ( [ ] dns . RR , error ) {
2014-11-26 02:59:18 +00:00
for _ , mx := range v . MX {
out = append ( out , mx )
}
return out , nil
}
2015-05-22 13:18:57 +00:00
func ( v * Value ) appendSRVs ( out [ ] dns . RR , suffix , apexSuffix string ) ( [ ] dns . RR , error ) {
for _ , svc := range v . SRV {
qn , ok := v . qualify ( svc . Target , suffix , apexSuffix )
if ! ok {
continue
}
out = append ( out , & dns . SRV {
Hdr : dns . RR_Header {
Name : "" ,
Rrtype : dns . TypeSRV ,
Class : dns . ClassINET ,
Ttl : defaultTTL ,
} ,
Priority : svc . Priority ,
Weight : svc . Weight ,
Port : svc . Port ,
Target : qn ,
} )
2014-11-26 02:59:18 +00:00
}
return out , nil
}
2015-11-12 05:18:02 +00:00
2014-12-01 00:44:06 +00:00
func ( v * Value ) appendTLSA ( out [ ] dns . RR , suffix , apexSuffix string ) ( [ ] dns . RR , error ) {
for _ , tlsa := range v . TLSA {
out = append ( out , tlsa )
}
2015-11-12 05:18:02 +00:00
for _ , cert := range v . TLSAGenerated {
template := cert
_ , nameNoPort := util . SplitDomainTail ( suffix )
_ , nameNoPortOrProtocol := util . SplitDomainTail ( nameNoPort )
derBytes , err := certdehydrate . FillRehydratedCertTemplate ( template , nameNoPortOrProtocol )
if err != nil {
// TODO: add debug output here
continue
}
derBytesHex := hex . EncodeToString ( derBytes )
out = append ( out , & dns . TLSA {
Hdr : dns . RR_Header { Name : suffix , Rrtype : dns . TypeTLSA , Class : dns . ClassINET ,
Ttl : defaultTTL } ,
Usage : uint8 ( 3 ) ,
Selector : uint8 ( 0 ) ,
MatchingType : uint8 ( 0 ) ,
Certificate : strings . ToUpper ( derBytesHex ) ,
} )
}
2014-12-01 00:44:06 +00:00
return out , nil
}
func ( v * Value ) appendAlias ( out [ ] dns . RR , suffix , apexSuffix string ) ( [ ] dns . RR , error ) {
if v . HasAlias {
qn , ok := v . qualify ( v . Alias , suffix , apexSuffix )
if ! ok {
return out , fmt . Errorf ( "bad alias" )
}
2014-11-26 02:59:18 +00:00
out = append ( out , & dns . CNAME {
Hdr : dns . RR_Header {
Name : suffix ,
Rrtype : dns . TypeCNAME ,
Class : dns . ClassINET ,
2014-12-04 12:04:14 +00:00
Ttl : defaultTTL ,
2014-11-26 02:59:18 +00:00
} ,
2014-12-01 00:44:06 +00:00
Target : qn ,
2014-11-26 02:59:18 +00:00
} )
}
return out , nil
}
2014-12-01 00:44:06 +00:00
func ( v * Value ) appendTranslate ( out [ ] dns . RR , suffix , apexSuffix string ) ( [ ] dns . RR , error ) {
if v . HasTranslate {
qn , ok := v . qualify ( v . Translate , suffix , apexSuffix )
if ! ok {
return out , fmt . Errorf ( "bad translate" )
}
2014-11-26 02:59:18 +00:00
out = append ( out , & dns . DNAME {
Hdr : dns . RR_Header {
Name : suffix ,
Rrtype : dns . TypeDNAME ,
Class : dns . ClassINET ,
2014-12-04 12:04:14 +00:00
Ttl : defaultTTL ,
2014-11-26 02:59:18 +00:00
} ,
2014-12-01 00:44:06 +00:00
Target : qn ,
2014-11-26 02:59:18 +00:00
} )
}
return out , nil
}
2014-12-01 00:44:06 +00:00
func ( v * Value ) RRsRecursive ( out [ ] dns . RR , suffix , apexSuffix string ) ( [ ] dns . RR , error ) {
out , err := v . RRs ( out , suffix , apexSuffix )
2014-11-26 02:59:18 +00:00
if err != nil {
return nil , err
}
for mk , mv := range v . Map {
2014-12-08 06:54:37 +00:00
if ! util . ValidateOwnerLabel ( mk ) && mk != "" && mk != "*" {
2014-11-27 20:36:21 +00:00
continue
2014-11-26 02:59:18 +00:00
}
2014-11-27 20:36:21 +00:00
2014-12-01 00:44:06 +00:00
out , err = mv . RRsRecursive ( out , mk + "." + suffix , apexSuffix )
2014-11-27 20:36:21 +00:00
//if err != nil {
// return nil, err
//}
2014-11-26 02:59:18 +00:00
}
return out , nil
}
2014-12-01 00:44:06 +00:00
func ( v * Value ) findSubdomainByName ( subdomain string ) ( * Value , error ) {
if subdomain == "" {
return v , nil
}
if strings . HasSuffix ( subdomain , "." ) {
return nil , fmt . Errorf ( "a subdomain name should not be fully qualified" )
}
head , rest := util . SplitDomainHead ( subdomain )
if sub , ok := v . Map [ head ] ; ok {
return sub . findSubdomainByName ( rest )
}
return nil , fmt . Errorf ( "subdomain part not found: %s" , head )
}
2014-11-26 02:59:18 +00:00
type ResolveFunc func ( name string ) ( string , error )
2014-12-06 09:30:14 +00:00
type ErrorFunc func ( err error , isWarning bool )
func ( ef ErrorFunc ) add ( err error ) {
if ef != nil && err != nil {
ef ( err , false )
}
}
func ( ef ErrorFunc ) addWarning ( err error ) {
if ef != nil && err != nil {
ef ( err , true )
}
}
2014-11-26 02:59:18 +00:00
// Call to convert a given JSON value to a parsed Namecoin domain value.
//
// If ResolveFunc is given, it will be called to obtain the values for domains
// referenced by "import" and "delegate" statements. The name passed is in
// Namecoin form (e.g. "d/example"). The JSON value or an error should be
// returned. If no ResolveFunc is passed, "import" and "delegate" statements
// always fail.
2014-12-06 09:30:14 +00:00
//
// Returns nil if the JSON could not be parsed. For all other errors processing
// continues and recovers as much as possible; errFunc is called for all errors
// and warnings if specified.
func ParseValue ( name , jsonValue string , resolve ResolveFunc , errFunc ErrorFunc ) ( value * Value ) {
2014-12-08 06:07:07 +00:00
var rv interface { }
2014-11-26 02:59:18 +00:00
v := & Value { }
2014-12-08 06:07:07 +00:00
err := json . Unmarshal ( [ ] byte ( jsonValue ) , & rv )
2014-11-26 02:59:18 +00:00
if err != nil {
2014-12-06 09:30:14 +00:00
errFunc . add ( err )
2014-11-26 02:59:18 +00:00
return
}
if resolve == nil {
resolve = func ( name string ) ( string , error ) {
return "" , fmt . Errorf ( "not supported" )
}
}
2014-12-01 00:44:06 +00:00
mergedNames := map [ string ] struct { } { }
mergedNames [ name ] = struct { } { }
2014-12-08 06:07:07 +00:00
parse ( rv , v , resolve , errFunc , 0 , 0 , "" , "" , mergedNames )
2014-12-01 00:44:06 +00:00
v . IsTopLevel = true
2014-11-26 02:59:18 +00:00
value = v
return
}
2014-12-08 06:07:07 +00:00
func parse ( rv interface { } , v * Value , resolve ResolveFunc , errFunc ErrorFunc , depth , mergeDepth int , subdomain , relname string , mergedNames map [ string ] struct { } ) {
rvm , ok := rv . ( map [ string ] interface { } )
if ! ok {
errFunc . add ( fmt . Errorf ( "value is not an object" ) )
return
}
2014-11-26 02:59:18 +00:00
if depth > depthLimit {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "depth limit exceeded" ) )
return
2014-11-26 02:59:18 +00:00
}
2014-12-01 00:44:06 +00:00
realv := v
if subdomain != "" {
// substitute a dummy value. We will then parse everything into this, find the appropriate level and copy
// the value to the argument value.
v = & Value { }
}
2014-12-08 06:07:07 +00:00
ok , _ = parseDelegate ( rvm , v , resolve , errFunc , depth , mergeDepth , relname , mergedNames )
2014-11-26 02:59:18 +00:00
if ok {
2014-12-06 09:30:14 +00:00
return
}
2014-12-08 06:07:07 +00:00
parseImport ( rvm , v , resolve , errFunc , depth , mergeDepth , relname , mergedNames )
if ip , ok := rvm [ "ip" ] ; ok {
parseIP ( rvm , v , errFunc , ip , false )
}
if ip6 , ok := rvm [ "ip6" ] ; ok {
parseIP ( rvm , v , errFunc , ip6 , true )
}
parseNS ( rvm , v , errFunc , relname )
parseAlias ( rvm , v , errFunc , relname )
parseTranslate ( rvm , v , errFunc , relname )
parseHostmaster ( rvm , v , errFunc )
parseDS ( rvm , v , errFunc )
parseTXT ( rvm , v , errFunc )
2015-05-22 13:18:57 +00:00
parseSRV ( rvm , v , errFunc , relname )
2014-12-08 06:07:07 +00:00
parseMX ( rvm , v , errFunc , relname )
parseTLSA ( rvm , v , errFunc )
parseMap ( rvm , v , resolve , errFunc , depth , mergeDepth , relname )
2014-11-26 02:59:18 +00:00
v . moveEmptyMapItems ( )
2014-12-01 00:44:06 +00:00
if subdomain != "" {
subv , err := v . findSubdomainByName ( subdomain )
if err != nil {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "couldn't find subdomain by name in import or delegate item: %v" , err ) )
return
2014-12-01 00:44:06 +00:00
}
* realv = * subv
}
2014-11-26 02:59:18 +00:00
}
2014-12-01 00:44:06 +00:00
func ( v * Value ) qualifyIntl ( name , suffix , apexSuffix string ) string {
if strings . HasSuffix ( name , "." ) {
return name
}
if ! v . IsTopLevel {
_ , suffix = util . SplitDomainTail ( suffix )
}
if name == "" {
return suffix
}
if name == "@" {
return apexSuffix
}
if strings . HasSuffix ( name , ".@" ) {
return name [ 0 : len ( name ) - 2 ] + "." + apexSuffix
}
return name + "." + suffix
}
func ( v * Value ) qualify ( name , suffix , apexSuffix string ) ( string , bool ) {
s := v . qualifyIntl ( name , suffix , apexSuffix )
2014-12-04 12:04:14 +00:00
if ! util . ValidateHostName ( s ) {
2014-12-01 00:44:06 +00:00
return "" , false
}
return s , true
}
2014-12-08 06:07:07 +00:00
func parseMerge ( rv map [ string ] interface { } , mergeValue string , v * Value , resolve ResolveFunc , errFunc ErrorFunc , depth , mergeDepth int , subdomain , relname string , mergedNames map [ string ] struct { } ) error {
var rv2 interface { }
2014-11-26 02:59:18 +00:00
if mergeDepth > mergeDepthLimit {
2014-12-06 09:30:14 +00:00
err := fmt . Errorf ( "merge depth limit exceeded" )
errFunc . add ( err )
return err
2014-11-26 02:59:18 +00:00
}
2014-12-08 06:07:07 +00:00
err := json . Unmarshal ( [ ] byte ( mergeValue ) , & rv2 )
2014-11-26 02:59:18 +00:00
if err != nil {
2014-12-06 09:30:14 +00:00
err = fmt . Errorf ( "couldn't parse JSON to be merged: %v" , err )
errFunc . add ( err )
2014-11-26 02:59:18 +00:00
return err
}
2014-12-08 06:07:07 +00:00
parse ( rv2 , v , resolve , errFunc , depth , mergeDepth , subdomain , relname , mergedNames )
2014-12-06 09:30:14 +00:00
return nil
2014-11-26 02:59:18 +00:00
}
2014-12-08 06:07:07 +00:00
func parseIP ( rv map [ string ] interface { } , v * Value , errFunc ErrorFunc , ipi interface { } , ipv6 bool ) {
if ipv6 {
v . IP6 = nil
} else {
v . IP = nil
}
if ipi == nil {
return
2014-11-26 02:59:18 +00:00
}
if ipa , ok := ipi . ( [ ] interface { } ) ; ok {
for _ , ip := range ipa {
if ips , ok := ip . ( string ) ; ok {
2014-12-08 06:07:07 +00:00
addIP ( rv , v , errFunc , ips , ipv6 )
2014-11-26 02:59:18 +00:00
}
}
return
}
if ip , ok := ipi . ( string ) ; ok {
2014-12-08 06:07:07 +00:00
addIP ( rv , v , errFunc , ip , ipv6 )
2014-11-26 02:59:18 +00:00
}
}
2014-12-08 06:07:07 +00:00
func addIP ( rv map [ string ] interface { } , v * Value , errFunc ErrorFunc , ips string , ipv6 bool ) {
2014-11-26 02:59:18 +00:00
pip := net . ParseIP ( ips )
if pip == nil || ( pip . To4 ( ) == nil ) != ipv6 {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "malformed IP: %s" , ips ) )
return
2014-11-26 02:59:18 +00:00
}
if ipv6 {
v . IP6 = append ( v . IP6 , pip )
} else {
v . IP = append ( v . IP , pip )
}
}
2014-12-08 06:07:07 +00:00
func parseNS ( rv map [ string ] interface { } , v * Value , errFunc ErrorFunc , relname string ) {
2014-11-26 02:59:18 +00:00
// "dns" takes precedence
2014-12-08 06:07:07 +00:00
if dns , ok := rv [ "dns" ] ; ok && dns != nil {
rv [ "ns" ] = dns
2014-11-26 02:59:18 +00:00
}
2014-12-08 06:07:07 +00:00
ns , ok := rv [ "ns" ]
if ! ok || ns == nil {
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
v . NS = nil
2014-12-08 06:07:07 +00:00
if _ , ok := rv [ "_nsSet" ] ; ! ok {
rv [ "_nsSet" ] = map [ string ] struct { } { }
2014-11-27 20:36:21 +00:00
}
2014-12-08 06:07:07 +00:00
switch ns . ( type ) {
2014-11-26 02:59:18 +00:00
case [ ] interface { } :
2014-12-08 06:07:07 +00:00
for _ , si := range ns . ( [ ] interface { } ) {
2014-11-26 02:59:18 +00:00
s , ok := si . ( string )
2014-11-27 20:36:21 +00:00
if ! ok {
2014-11-26 02:59:18 +00:00
continue
}
2014-12-08 06:07:07 +00:00
addNS ( rv , v , errFunc , s , relname )
2014-11-26 02:59:18 +00:00
}
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
case string :
2014-12-08 06:07:07 +00:00
s := ns . ( string )
addNS ( rv , v , errFunc , s , relname )
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
default :
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "unknown NS field format" ) )
2014-11-26 02:59:18 +00:00
}
}
2014-12-08 06:07:07 +00:00
func addNS ( rv map [ string ] interface { } , v * Value , errFunc ErrorFunc , s , relname string ) {
if ! util . ValidateOwnerName ( s ) {
errFunc . add ( fmt . Errorf ( "malformed domain name in NS field" ) )
}
if _ , ok := ( rv [ "_nsSet" ] . ( map [ string ] struct { } ) ) [ s ] ; ! ok {
2014-11-27 20:36:21 +00:00
v . NS = append ( v . NS , s )
2014-12-08 06:07:07 +00:00
( rv [ "_nsSet" ] . ( map [ string ] struct { } ) ) [ s ] = struct { } { }
2014-11-27 20:36:21 +00:00
}
}
2014-12-08 06:07:07 +00:00
func parseAlias ( rv map [ string ] interface { } , v * Value , errFunc ErrorFunc , relname string ) {
alias , ok := rv [ "alias" ]
if ! ok {
return
}
if alias == nil {
v . Alias = ""
v . HasAlias = false
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
2014-12-08 06:07:07 +00:00
if s , ok := alias . ( string ) ; ok {
2014-12-08 06:54:37 +00:00
if ! util . ValidateRelOwnerName ( s ) {
2014-12-08 06:07:07 +00:00
errFunc . add ( fmt . Errorf ( "malformed alias name" ) )
return
}
2014-11-26 02:59:18 +00:00
v . Alias = s
2014-12-01 00:44:06 +00:00
v . HasAlias = true
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "unknown alias field format" ) )
2014-11-26 02:59:18 +00:00
}
2014-12-08 06:07:07 +00:00
func parseTranslate ( rv map [ string ] interface { } , v * Value , errFunc ErrorFunc , relname string ) {
translate , ok := rv [ "translate" ]
if ! ok {
return
}
if translate == nil {
v . Translate = ""
v . HasTranslate = false
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
2014-12-08 06:07:07 +00:00
if s , ok := translate . ( string ) ; ok {
2014-12-08 06:54:37 +00:00
if ! util . ValidateRelOwnerName ( s ) {
2014-12-08 06:07:07 +00:00
errFunc . add ( fmt . Errorf ( "malformed translate name" ) )
return
}
2014-11-26 02:59:18 +00:00
v . Translate = s
2014-12-01 00:44:06 +00:00
v . HasTranslate = true
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "unknown translate field format" ) )
2014-11-26 02:59:18 +00:00
}
2014-12-01 00:44:06 +00:00
func isAllArray ( x [ ] interface { } ) bool {
for _ , v := range x {
if _ , ok := v . ( [ ] interface { } ) ; ! ok {
return false
}
2014-11-26 02:59:18 +00:00
}
2014-12-01 00:44:06 +00:00
return true
}
2014-11-26 02:59:18 +00:00
2014-12-01 00:44:06 +00:00
func isAllString ( x [ ] interface { } ) bool {
for _ , v := range x {
if _ , ok := v . ( string ) ; ! ok {
return false
2014-11-26 02:59:18 +00:00
}
}
2014-12-01 00:44:06 +00:00
return true
2014-11-26 02:59:18 +00:00
}
2014-12-08 06:07:07 +00:00
func parseImportImpl ( rv map [ string ] interface { } , val * Value , resolve ResolveFunc , errFunc ErrorFunc , depth , mergeDepth int , relname string , mergedNames map [ string ] struct { } , delegate bool ) ( bool , error ) {
2014-12-01 00:44:06 +00:00
var err error
succeeded := false
2014-12-08 06:07:07 +00:00
xname := "import"
2014-12-01 00:44:06 +00:00
if delegate {
2014-12-08 06:07:07 +00:00
xname = "delegate"
2014-12-01 00:44:06 +00:00
}
2014-12-08 06:07:07 +00:00
src , ok := rv [ xname ]
if ! ok || src == nil {
2014-11-26 02:59:18 +00:00
return false , nil
}
2014-12-01 00:44:06 +00:00
if s , ok := src . ( string ) ; ok {
src = [ ] interface { } { s }
}
if a , ok := src . ( [ ] interface { } ) ; ok {
// [..., ..., ...]
if isAllString ( a ) {
// ["s/somedomain"]
// ["s/somedomain", "sub.domain"]
a = [ ] interface { } { a }
}
if isAllArray ( a ) {
// [ ["s/somedomain", "sub.domain"], ["s/somedomain", "sub.domain"] ]
for _ , vx := range a {
v := vx . ( [ ] interface { } )
if len ( v ) != 1 && len ( v ) != 2 {
continue
}
subs := ""
if k , ok := v [ 0 ] . ( string ) ; ok {
if len ( v ) > 1 {
if sub , ok := v [ 1 ] . ( string ) ; ok {
subs = sub
}
}
2014-12-24 17:05:17 +00:00
if _ , ok := mergedNames [ k ] ; ok {
// already merged
continue
}
2014-12-01 00:44:06 +00:00
// ok
var dv string
dv , err = resolve ( k )
if err != nil {
continue
}
mergedNames [ k ] = struct { } { }
2014-12-08 06:07:07 +00:00
err = parseMerge ( rv , dv , val , resolve , errFunc , depth , mergeDepth + 1 , subs , relname , mergedNames )
2014-12-01 00:44:06 +00:00
if err != nil {
2014-12-06 09:30:14 +00:00
errFunc . add ( err )
2014-12-01 00:44:06 +00:00
continue
}
succeeded = true
}
}
2014-12-06 09:30:14 +00:00
// ...
return succeeded , nil
2014-11-26 02:59:18 +00:00
}
2014-12-01 00:44:06 +00:00
// malformed
}
if err == nil {
err = fmt . Errorf ( "unknown import/delegate field format" )
2014-11-26 02:59:18 +00:00
}
2014-12-06 09:30:14 +00:00
errFunc . add ( err )
2014-12-01 00:44:06 +00:00
return succeeded , err
}
2014-12-08 06:07:07 +00:00
func parseImport ( rv map [ string ] interface { } , v * Value , resolve ResolveFunc , errFunc ErrorFunc , depth , mergeDepth int , relname string , mergedNames map [ string ] struct { } ) error {
_ , err := parseImportImpl ( rv , v , resolve , errFunc , depth , mergeDepth , relname , mergedNames , false )
2014-12-01 00:44:06 +00:00
return err
}
2014-12-08 06:07:07 +00:00
func parseDelegate ( rv map [ string ] interface { } , v * Value , resolve ResolveFunc , errFunc ErrorFunc , depth , mergeDepth int , relname string , mergedNames map [ string ] struct { } ) ( bool , error ) {
return parseImportImpl ( rv , v , resolve , errFunc , depth , mergeDepth , relname , mergedNames , true )
2014-11-26 02:59:18 +00:00
}
2014-12-08 06:07:07 +00:00
func parseHostmaster ( rv map [ string ] interface { } , v * Value , errFunc ErrorFunc ) {
hm , ok := rv [ "email" ]
if ! ok || hm == nil {
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
2014-12-08 06:07:07 +00:00
if s , ok := hm . ( string ) ; ok {
2014-12-04 12:04:14 +00:00
if ! util . ValidateEmail ( s ) {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "malformed e. mail address in email field" ) )
return
2014-11-26 02:59:18 +00:00
}
v . Hostmaster = s
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "unknown email field format" ) )
2014-11-26 02:59:18 +00:00
}
2014-12-08 06:07:07 +00:00
func parseDS ( rv map [ string ] interface { } , v * Value , errFunc ErrorFunc ) {
rds , ok := rv [ "ds" ]
if ! ok || rds == nil {
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
v . DS = nil
2014-12-08 06:07:07 +00:00
if dsa , ok := rds . ( [ ] interface { } ) ; ok {
2014-11-26 02:59:18 +00:00
for _ , ds1 := range dsa {
if ds , ok := ds1 . ( [ ] interface { } ) ; ok {
2014-12-06 09:30:14 +00:00
if len ( ds ) < 4 {
errFunc . add ( fmt . Errorf ( "DS item must have four items" ) )
2014-11-26 02:59:18 +00:00
continue
}
a1 , ok := ds [ 0 ] . ( float64 )
if ! ok {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "First item in DS value must be an integer (key tag)" ) )
2014-11-26 02:59:18 +00:00
continue
}
a2 , ok := ds [ 1 ] . ( float64 )
if ! ok {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "Second item in DS value must be an integer (algorithm)" ) )
2014-11-26 02:59:18 +00:00
continue
}
a3 , ok := ds [ 2 ] . ( float64 )
if ! ok {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "Third item in DS value must be an integer (digest type)" ) )
2014-11-26 02:59:18 +00:00
continue
}
a4 , ok := ds [ 3 ] . ( string )
if ! ok {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "Fourth item in DS value must be a string (digest)" ) )
2014-11-26 02:59:18 +00:00
continue
}
a4b , err := base64 . StdEncoding . DecodeString ( a4 )
if err != nil {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "Fourth item in DS value must be valid base64: %v" , err ) )
2014-11-26 02:59:18 +00:00
continue
}
a4h := hex . EncodeToString ( a4b )
v . DS = append ( v . DS , & dns . DS {
2014-12-04 12:04:14 +00:00
Hdr : dns . RR_Header { Rrtype : dns . TypeDS , Class : dns . ClassINET , Ttl : defaultTTL } ,
2014-11-26 02:59:18 +00:00
KeyTag : uint16 ( a1 ) ,
Algorithm : uint8 ( a2 ) ,
DigestType : uint8 ( a3 ) ,
Digest : a4h ,
} )
2014-12-06 09:30:14 +00:00
} else {
errFunc . add ( fmt . Errorf ( "DS item must be an array" ) )
2014-11-26 02:59:18 +00:00
}
}
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
2014-12-01 00:44:06 +00:00
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "malformed DS field format" ) )
2014-11-26 02:59:18 +00:00
}
2015-11-12 05:18:02 +00:00
func parseTLSADehydrated ( tlsa1dehydrated interface { } , v * Value ) error {
dehydrated , err := certdehydrate . ParseDehydratedCert ( tlsa1dehydrated )
if err != nil {
return fmt . Errorf ( "Error parsing dehydrated certificate: %s" , err )
}
template , err := certdehydrate . RehydrateCert ( dehydrated )
if err != nil {
return fmt . Errorf ( "Error rehydrating certificate: %s" , err )
}
v . TLSAGenerated = append ( v . TLSAGenerated , * template )
return nil
}
func parseTLSADANE ( tlsa1dane interface { } , v * Value ) error {
if tlsa , ok := tlsa1dane . ( [ ] interface { } ) ; ok {
// Format: ["443", "tcp", 1, 2, 3, "base64 certificate data"]
if len ( tlsa ) < 4 {
return fmt . Errorf ( "TLSA item must have six items" )
}
a1 , ok := tlsa [ 0 ] . ( float64 )
if ! ok {
return fmt . Errorf ( "Third item in TLSA value must be an integer (usage)" )
}
a2 , ok := tlsa [ 1 ] . ( float64 )
if ! ok {
return fmt . Errorf ( "Fourth item in TLSA value must be an integer (selector)" )
}
a3 , ok := tlsa [ 2 ] . ( float64 )
if ! ok {
return fmt . Errorf ( "Fifth item in TLSA value must be an integer (match type)" )
}
a4 , ok := tlsa [ 3 ] . ( string )
if ! ok {
return fmt . Errorf ( "Sixth item in TLSA value must be a string (certificate)" )
}
a4b , err := base64 . StdEncoding . DecodeString ( a4 )
if err != nil {
return fmt . Errorf ( "Fourth item in DS value must be valid base64: %v" , err )
}
a4h := hex . EncodeToString ( a4b )
v . TLSA = append ( v . TLSA , & dns . TLSA {
Hdr : dns . RR_Header { Name : "" , Rrtype : dns . TypeTLSA , Class : dns . ClassINET ,
Ttl : defaultTTL } ,
Usage : uint8 ( a1 ) ,
Selector : uint8 ( a2 ) ,
MatchingType : uint8 ( a3 ) ,
Certificate : strings . ToUpper ( a4h ) ,
} )
return nil
} else {
return fmt . Errorf ( "TLSA item must be an array" )
}
}
2014-12-08 06:07:07 +00:00
func parseTLSA ( rv map [ string ] interface { } , v * Value , errFunc ErrorFunc ) {
tlsa , ok := rv [ "tls" ]
if ! ok || tlsa == nil {
2014-12-06 09:30:14 +00:00
return
2014-12-01 00:44:06 +00:00
}
v . TLSA = nil
2014-12-08 06:07:07 +00:00
if tlsaa , ok := tlsa . ( [ ] interface { } ) ; ok {
2014-12-01 00:44:06 +00:00
for _ , tlsa1 := range tlsaa {
2015-11-12 05:18:02 +00:00
var tlsa1m map [ string ] interface { }
2014-12-01 00:44:06 +00:00
2015-11-12 05:18:02 +00:00
if _ , ok := tlsa1 . ( [ ] interface { } ) ; ok {
tlsa1m = map [ string ] interface { } {
"dane" : tlsa1 ,
2014-12-01 00:44:06 +00:00
}
2015-11-12 05:18:02 +00:00
} else {
tlsa1m = tlsa1 . ( map [ string ] interface { } )
}
2014-12-01 00:44:06 +00:00
2015-11-12 05:18:02 +00:00
if tlsa1dehydrated , ok := tlsa1m [ "d8" ] ; ok {
err := parseTLSADehydrated ( tlsa1dehydrated , v )
if err == nil {
2014-12-01 00:44:06 +00:00
continue
}
2015-11-12 05:18:02 +00:00
errFunc . add ( err )
}
2014-12-01 00:44:06 +00:00
2015-11-12 05:18:02 +00:00
if tlsa1dane , ok := tlsa1m [ "dane" ] ; ok {
err := parseTLSADANE ( tlsa1dane , v )
if err == nil {
2014-12-06 09:30:14 +00:00
continue
}
2015-11-12 05:18:02 +00:00
errFunc . add ( err )
2014-12-01 00:44:06 +00:00
}
2015-11-12 05:18:02 +00:00
errFunc . add ( fmt . Errorf ( "Unknown TLSA item format" ) )
2014-12-01 00:44:06 +00:00
}
2014-12-06 09:30:14 +00:00
return
2014-12-01 00:44:06 +00:00
}
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "Malformed TLSA field format" ) )
2014-12-01 00:44:06 +00:00
}
2014-12-08 06:07:07 +00:00
func parseTXT ( rv map [ string ] interface { } , v * Value , errFunc ErrorFunc ) {
rtxt , ok := rv [ "txt" ]
if ! ok || rtxt == nil {
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
2014-12-08 06:07:07 +00:00
if txta , ok := rtxt . ( [ ] interface { } ) ; ok {
2014-11-26 02:59:18 +00:00
// ["...", "..."] or [["...", "..."], ["...", "..."]]
for _ , vv := range txta {
if sa , ok := vv . ( [ ] interface { } ) ; ok {
// [["...", "..."], ["...", "..."]]
a := [ ] string { }
for _ , x := range sa {
2014-11-27 20:36:21 +00:00
if xs , ok := x . ( string ) ; ok && len ( xs ) <= 255 {
2014-11-26 02:59:18 +00:00
a = append ( a , xs )
}
}
2014-11-27 20:36:21 +00:00
if len ( a ) > 0 {
v . TXT = append ( v . TXT , a )
}
2014-11-26 02:59:18 +00:00
} else if s , ok := vv . ( string ) ; ok {
v . TXT = append ( v . TXT , segmentizeTXT ( s ) )
} else {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "malformed TXT value" ) )
return
2014-11-26 02:59:18 +00:00
}
}
} else {
// "..."
2014-12-08 06:07:07 +00:00
if s , ok := rtxt . ( string ) ; ok {
2014-11-26 02:59:18 +00:00
v . TXT = append ( v . TXT , segmentizeTXT ( s ) )
} else {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "malformed TXT value" ) )
return
2014-11-26 02:59:18 +00:00
}
}
2014-11-27 20:36:21 +00:00
// Make sure the content of each TXT record does not exceed 65535 bytes.
for i := range v . TXT {
for {
L := 0
for j := range v . TXT [ i ] {
L += len ( v . TXT [ i ] [ j ] ) + 1
}
if L <= 65535 {
break
}
// Pop segments until under the limit.
v . TXT [ i ] = v . TXT [ i ] [ 0 : len ( v . TXT [ i ] ) - 1 ]
}
}
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
func segmentizeTXT ( txt string ) ( a [ ] string ) {
for len ( txt ) > 255 {
a = append ( a , txt [ 0 : 255 ] )
txt = txt [ 255 : ]
}
a = append ( a , txt )
return
}
2014-12-08 06:07:07 +00:00
func parseMX ( rv map [ string ] interface { } , v * Value , errFunc ErrorFunc , relname string ) {
rmx , ok := rv [ "mx" ]
if ! ok || rmx == nil {
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
2014-12-08 06:07:07 +00:00
if sa , ok := rmx . ( [ ] interface { } ) ; ok {
2014-11-26 02:59:18 +00:00
for _ , s := range sa {
2014-12-08 06:07:07 +00:00
parseSingleMX ( rv , s , v , errFunc , relname )
2014-11-26 02:59:18 +00:00
}
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "malformed MX value" ) )
2014-11-26 02:59:18 +00:00
}
2014-12-08 06:07:07 +00:00
func parseSingleMX ( rv map [ string ] interface { } , s interface { } , v * Value , errFunc ErrorFunc , relname string ) {
2014-11-26 02:59:18 +00:00
sa , ok := s . ( [ ] interface { } )
if ! ok {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "malformed MX value" ) )
return
2014-11-26 02:59:18 +00:00
}
if len ( sa ) < 2 {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "malformed MX value" ) )
return
2014-11-26 02:59:18 +00:00
}
prio , ok := sa [ 0 ] . ( float64 )
if ! ok || prio < 0 {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "malformed MX value" ) )
return
2014-11-26 02:59:18 +00:00
}
hostname , ok := sa [ 1 ] . ( string )
2014-12-01 00:44:06 +00:00
if ! ok {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "malformed MX value" ) )
return
2014-11-26 02:59:18 +00:00
}
v . MX = append ( v . MX , & dns . MX {
2014-12-04 12:04:14 +00:00
Hdr : dns . RR_Header { Rrtype : dns . TypeMX , Class : dns . ClassINET , Ttl : defaultTTL } ,
2014-11-26 02:59:18 +00:00
Preference : uint16 ( prio ) ,
Mx : hostname ,
} )
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
2015-05-22 13:18:57 +00:00
func parseSRV ( rv map [ string ] interface { } , v * Value , errFunc ErrorFunc , relname string ) {
rsvc , ok := rv [ "srv" ]
2014-12-08 06:07:07 +00:00
if ! ok || rsvc == nil {
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
2015-05-22 13:18:57 +00:00
v . SRV = nil
2014-12-01 00:44:06 +00:00
2014-12-08 06:07:07 +00:00
if sa , ok := rsvc . ( [ ] interface { } ) ; ok {
2014-11-26 02:59:18 +00:00
for _ , s := range sa {
2015-05-22 13:18:57 +00:00
parseSingleService ( rv , s , v , errFunc , relname )
2014-12-01 00:44:06 +00:00
}
2014-12-06 09:30:14 +00:00
} else {
errFunc . add ( fmt . Errorf ( "malformed service value" ) )
2014-12-01 00:44:06 +00:00
}
2014-11-26 02:59:18 +00:00
}
2015-05-22 13:18:57 +00:00
func parseSingleService ( rv map [ string ] interface { } , svc interface { } , v * Value , errFunc ErrorFunc , relname string ) {
2014-11-26 02:59:18 +00:00
svca , ok := svc . ( [ ] interface { } )
if ! ok {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "malformed service value" ) )
return
2014-11-26 02:59:18 +00:00
}
2015-05-22 13:18:57 +00:00
if len ( svca ) < 4 {
errFunc . add ( fmt . Errorf ( "malformed service value: must have four items" ) )
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
2015-05-22 13:18:57 +00:00
//servicesUsed[sname] = struct{}{}
2014-11-26 02:59:18 +00:00
2015-05-22 13:18:57 +00:00
priority , ok := svca [ 0 ] . ( float64 )
2014-11-26 02:59:18 +00:00
if ! ok {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "malformed service value: third item must be an integer (priority)" ) )
return
2014-11-26 02:59:18 +00:00
}
2015-05-22 13:18:57 +00:00
weight , ok := svca [ 1 ] . ( float64 )
2014-11-26 02:59:18 +00:00
if ! ok {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "malformed service value: fourth item must be an integer (weight)" ) )
return
2014-11-26 02:59:18 +00:00
}
2015-05-22 13:18:57 +00:00
port , ok := svca [ 2 ] . ( float64 )
2014-11-26 02:59:18 +00:00
if ! ok {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "malformed service value: fifth item must be an integer (port number)" ) )
return
2014-11-26 02:59:18 +00:00
}
2015-05-22 13:18:57 +00:00
hostname , ok := svca [ 3 ] . ( string )
2014-12-01 00:44:06 +00:00
if ! ok {
2014-12-06 09:30:14 +00:00
errFunc . add ( fmt . Errorf ( "malformed service value: sixth item must be a string (target)" ) )
return
2014-11-26 02:59:18 +00:00
}
2015-05-22 13:18:57 +00:00
v . SRV = append ( v . SRV , & dns . SRV {
2014-11-26 02:59:18 +00:00
Hdr : dns . RR_Header {
2015-05-22 13:18:57 +00:00
Name : "" ,
2014-11-26 02:59:18 +00:00
Rrtype : dns . TypeSRV ,
Class : dns . ClassINET ,
2014-12-04 12:04:14 +00:00
Ttl : defaultTTL ,
2014-11-26 02:59:18 +00:00
} ,
Priority : uint16 ( priority ) ,
Weight : uint16 ( weight ) ,
Port : uint16 ( port ) ,
Target : hostname ,
} )
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
2014-12-12 11:23:00 +00:00
func convServiceValue ( x interface { } ) ( string , error ) {
if x == nil {
return "" , nil
} else if f , ok := x . ( float64 ) ; ok {
return strconv . FormatInt ( int64 ( f ) , 10 ) , nil
} else if s , ok := x . ( string ) ; ok {
return s , nil
} else {
return "" , fmt . Errorf ( "malformed value: first item must be a string (application protocol)" )
}
}
2014-12-08 06:07:07 +00:00
func parseMap ( rv map [ string ] interface { } , v * Value , resolve ResolveFunc , errFunc ErrorFunc , depth , mergeDepth int , relname string ) {
rmap , ok := rv [ "map" ]
if ! ok || rmap == nil {
2014-12-06 09:30:14 +00:00
return
}
2014-12-08 06:07:07 +00:00
m , ok := rmap . ( map [ string ] interface { } )
if ! ok {
errFunc . add ( fmt . Errorf ( "Map value must be an object" ) )
2014-12-06 09:30:14 +00:00
return
2014-11-26 02:59:18 +00:00
}
for mk , mv := range m {
2014-12-08 06:07:07 +00:00
if s , ok := mv . ( string ) ; ok {
2014-11-26 02:59:18 +00:00
// deprecated case: "map": { "": "127.0.0.1" }
2014-12-08 06:07:07 +00:00
mv = map [ string ] interface { } { "ip" : [ ] interface { } { s } }
m [ mk ] = mv
2014-11-26 02:59:18 +00:00
}
2014-12-08 06:07:07 +00:00
if mvm , ok := mv . ( map [ string ] interface { } ) ; ok {
if v . Map == nil {
v . Map = make ( map [ string ] * Value )
}
2015-05-22 13:18:57 +00:00
v2 := & Value { }
if v2e , ok := v . Map [ mk ] ; ok {
v2 = v2e
}
mergedNames := map [ string ] struct { } { }
parse ( mvm , v2 , resolve , errFunc , depth + 1 , mergeDepth , "" , relname , mergedNames )
2014-12-08 06:07:07 +00:00
v . Map [ mk ] = v2
2014-11-26 02:59:18 +00:00
2014-12-08 06:07:07 +00:00
} else {
errFunc . add ( fmt . Errorf ( "Value in map object must be an object or string" ) )
continue
}
2014-11-26 02:59:18 +00:00
}
}
// Moves items in {"map": {"": ...}} to the object itself, then deletes the ""
// entry in the map object.
2014-12-06 09:30:14 +00:00
func ( v * Value ) moveEmptyMapItems ( ) {
2014-11-26 02:59:18 +00:00
if ev , ok := v . Map [ "" ] ; ok {
if len ( v . IP ) == 0 {
v . IP = ev . IP
}
if len ( v . IP6 ) == 0 {
v . IP6 = ev . IP6
}
if len ( v . NS ) == 0 {
v . NS = ev . NS
}
if len ( v . DS ) == 0 {
v . DS = ev . DS
}
if len ( v . TXT ) == 0 {
v . TXT = ev . TXT
}
2015-05-22 13:18:57 +00:00
if len ( v . SRV ) == 0 {
v . SRV = ev . SRV
2014-11-26 02:59:18 +00:00
}
if len ( v . MX ) == 0 {
v . MX = ev . MX
}
if len ( v . Alias ) == 0 {
v . Alias = ev . Alias
}
if len ( v . Translate ) == 0 {
v . Translate = ev . Translate
}
if len ( v . Hostmaster ) == 0 {
v . Hostmaster = ev . Hostmaster
}
delete ( v . Map , "" )
if len ( v . Map ) == 0 {
v . Map = ev . Map
}
}
}