diff --git a/ncdomain/convert.go b/ncdomain/convert.go index f33d091..9450498 100644 --- a/ncdomain/convert.go +++ b/ncdomain/convert.go @@ -37,10 +37,10 @@ type Value struct { HasTranslate bool // True if Translate was specified. Necessary as "" is a valid relative value for Translate. DS []*dns.DS TXT [][]string - Service []*dns.SRV // header name contains e.g. "_http._tcp" - Hostmaster string // "hostmaster@example.com" - MX []*dns.MX // header name is left blank - TLSA []*dns.TLSA // header name contains e.g. "_443._tcp" + SRV []*dns.SRV + Hostmaster string // "hostmaster@example.com" + MX []*dns.MX // header name is left blank + TLSA []*dns.TLSA Map map[string]*Value // may contain and "*", will not contain "" // set if the value is at the top level (alas necessary for relname interpretation) @@ -77,7 +77,7 @@ func (v *Value) mkString(i string) string { s += i + " " + txtc } } - for _, srv := range v.Service { + for _, srv := range v.SRV { s += i + "SRV Record: " + srv.String() } for _, tlsa := range v.TLSA { @@ -112,10 +112,9 @@ func (v *Value) RRs(out []dns.RR, suffix, apexSuffix string) ([]dns.RR, error) { out, _ = v.appendIP6s(out, suffix, apexSuffix) out, _ = v.appendTXTs(out, suffix, apexSuffix) out, _ = v.appendMXs(out, suffix, apexSuffix) + out, _ = v.appendSRVs(out, suffix, apexSuffix) + out, _ = v.appendTLSA(out, suffix, apexSuffix) } - // SRV and TLSA records are assigned to a subdomain, but CNAMEs are not recursive so CNAME must not inhibit them - out, _ = v.appendServices(out, suffix, apexSuffix) - out, _ = v.appendTLSA(out, suffix, apexSuffix) } } out, _ = v.appendDSs(out, suffix, apexSuffix) @@ -222,9 +221,25 @@ func (v *Value) appendMXs(out []dns.RR, suffix, apexSuffix string) ([]dns.RR, er return out, nil } -func (v *Value) appendServices(out []dns.RR, suffix, apexSuffix string) ([]dns.RR, error) { - for _, svc := range v.Service { - out = append(out, svc) +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, + }) } return out, nil @@ -405,7 +420,7 @@ func parse(rv interface{}, v *Value, resolve ResolveFunc, errFunc ErrorFunc, dep parseHostmaster(rvm, v, errFunc) parseDS(rvm, v, errFunc) parseTXT(rvm, v, errFunc) - parseService(rvm, v, errFunc, relname) + parseSRV(rvm, v, errFunc, relname) parseMX(rvm, v, errFunc, relname) parseTLSA(rvm, v, errFunc) parseMap(rvm, v, resolve, errFunc, depth, mergeDepth, relname) @@ -814,36 +829,30 @@ func parseTLSA(rv map[string]interface{}, v *Value, errFunc ErrorFunc) { for _, tlsa1 := range tlsaa { if tlsa, ok := tlsa1.([]interface{}); ok { // Format: ["443", "tcp", 1, 2, 3, "base64 certificate data"] - if len(tlsa) < 6 { + if len(tlsa) < 4 { errFunc.add(fmt.Errorf("TLSA item must have six items")) continue } - sname, err := deriveServicePrefix(tlsa[0], tlsa[1]) - if err != nil { - errFunc.add(err) - continue - } - - a1, ok := tlsa[2].(float64) + a1, ok := tlsa[0].(float64) if !ok { errFunc.add(fmt.Errorf("Third item in TLSA value must be an integer (usage)")) continue } - a2, ok := tlsa[3].(float64) + a2, ok := tlsa[1].(float64) if !ok { errFunc.add(fmt.Errorf("Fourth item in TLSA value must be an integer (selector)")) continue } - a3, ok := tlsa[4].(float64) + a3, ok := tlsa[2].(float64) if !ok { errFunc.add(fmt.Errorf("Fifth item in TLSA value must be an integer (match type)")) continue } - a4, ok := tlsa[5].(string) + a4, ok := tlsa[3].(string) if !ok { errFunc.add(fmt.Errorf("Sixth item in TLSA value must be a string (certificate)")) continue @@ -858,7 +867,7 @@ func parseTLSA(rv map[string]interface{}, v *Value, errFunc ErrorFunc) { a4h := hex.EncodeToString(a4b) v.TLSA = append(v.TLSA, &dns.TLSA{ - Hdr: dns.RR_Header{Name: sname, Rrtype: dns.TypeTLSA, Class: dns.ClassINET, + Hdr: dns.RR_Header{Name: "", Rrtype: dns.TypeTLSA, Class: dns.ClassINET, Ttl: defaultTTL}, Usage: uint8(a1), Selector: uint8(a2), @@ -991,80 +1000,64 @@ func parseSingleMX(rv map[string]interface{}, s interface{}, v *Value, errFunc E return } -func parseService(rv map[string]interface{}, v *Value, errFunc ErrorFunc, relname string) { - rsvc, ok := rv["service"] +func parseSRV(rv map[string]interface{}, v *Value, errFunc ErrorFunc, relname string) { + rsvc, ok := rv["srv"] if !ok || rsvc == nil { return } - // We have to merge the services specified and those imported using an - // import statement. - servicesUsed := map[string]struct{}{} - oldServices := v.Service - v.Service = nil + v.SRV = nil if sa, ok := rsvc.([]interface{}); ok { for _, s := range sa { - parseSingleService(rv, s, v, errFunc, relname, servicesUsed) + parseSingleService(rv, s, v, errFunc, relname) } } else { errFunc.add(fmt.Errorf("malformed service value")) } - - for _, svc := range oldServices { - if _, ok := servicesUsed[svc.Header().Name]; !ok { - v.Service = append(v.Service, svc) - } - } } -func parseSingleService(rv map[string]interface{}, svc interface{}, v *Value, errFunc ErrorFunc, relname string, servicesUsed map[string]struct{}) { +func parseSingleService(rv map[string]interface{}, svc interface{}, v *Value, errFunc ErrorFunc, relname string) { svca, ok := svc.([]interface{}) if !ok { errFunc.add(fmt.Errorf("malformed service value")) return } - if len(svca) < 6 { - errFunc.add(fmt.Errorf("malformed service value: must have six items")) - return - } - - sname, err := deriveServicePrefix(svca[0], svca[1]) - if err != nil { - errFunc.add(err) + if len(svca) < 4 { + errFunc.add(fmt.Errorf("malformed service value: must have four items")) return } - servicesUsed[sname] = struct{}{} + //servicesUsed[sname] = struct{}{} - priority, ok := svca[2].(float64) + priority, ok := svca[0].(float64) if !ok { errFunc.add(fmt.Errorf("malformed service value: third item must be an integer (priority)")) return } - weight, ok := svca[3].(float64) + weight, ok := svca[1].(float64) if !ok { errFunc.add(fmt.Errorf("malformed service value: fourth item must be an integer (weight)")) return } - port, ok := svca[4].(float64) + port, ok := svca[2].(float64) if !ok { errFunc.add(fmt.Errorf("malformed service value: fifth item must be an integer (port number)")) return } - hostname, ok := svca[5].(string) + hostname, ok := svca[3].(string) if !ok { errFunc.add(fmt.Errorf("malformed service value: sixth item must be a string (target)")) return } - v.Service = append(v.Service, &dns.SRV{ + v.SRV = append(v.SRV, &dns.SRV{ Hdr: dns.RR_Header{ - Name: sname, + Name: "", Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: defaultTTL, @@ -1090,39 +1083,6 @@ func convServiceValue(x interface{}) (string, error) { } } -func deriveServicePrefixPart(x interface{}) (string, error) { - xs, err := convServiceValue(x) - if err != nil { - return "", err - } - - if len(xs) == 0 { - return "", nil - } - - if xs == "*" { - return "*.", nil - } - - if !util.ValidateServiceName(xs) { - return "", fmt.Errorf("malformed service name") - } - - return "_" + xs + ".", nil -} - -func deriveServicePrefix(x, y interface{}) (string, error) { - xs, err := deriveServicePrefixPart(x) - if err != nil { - return "", err - } - ys, err := deriveServicePrefixPart(y) - if err != nil { - return "", err - } - return xs + ys, nil -} - 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 { @@ -1143,14 +1103,18 @@ func parseMap(rv map[string]interface{}, v *Value, resolve ResolveFunc, errFunc } if mvm, ok := mv.(map[string]interface{}); ok { - v2 := &Value{} - mergedNames := map[string]struct{}{} - parse(mvm, v2, resolve, errFunc, depth+1, mergeDepth, "", relname, mergedNames) - if v.Map == nil { v.Map = make(map[string]*Value) } + 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) + v.Map[mk] = v2 } else { @@ -1179,8 +1143,8 @@ func (v *Value) moveEmptyMapItems() { if len(v.TXT) == 0 { v.TXT = ev.TXT } - if len(v.Service) == 0 { - v.Service = ev.Service + if len(v.SRV) == 0 { + v.SRV = ev.SRV } if len(v.MX) == 0 { v.MX = ev.MX