// Convert a DS request object into a DS model object. It can return errors related to the // conversion of the algorithm, when it is out of range func (d *DSRequest) toDSModel() (model.DS, error) { ds := model.DS{ Keytag: d.Keytag, Digest: model.NormalizeDSDigest(d.Digest), } if !model.IsValidDSAlgorithm(d.Algorithm) { return ds, ErrInvalidDSAlgorithm } ds.Algorithm = model.DSAlgorithm(d.Algorithm) if !model.IsValidDSDigestType(d.DigestType) { return ds, ErrInvalidDSDigestType } ds.DigestType = model.DSDigestType(d.DigestType) return ds, nil }
// Function to read input data file for performance tests. The file must use the following // format: // // <zonename1> <type1> <data1> // <zonename2> <type2> <data2> // ... // <zonenameN> <typeN> <dataN> // // Where type can be NS, A, AAAA or DS. All types, except for DS, will have only one field // in data, for DS we will have four fields. For example: // // br. NS a.dns.br. // br. NS b.dns.br. // br. NS c.dns.br. // br. NS d.dns.br. // br. NS e.dns.br. // br. NS f.dns.br. // br. DS 41674 5 1 EAA0978F38879DB70A53F9FF1ACF21D046A98B5C // a.dns.br. A 200.160.0.10 // a.dns.br. AAAA 2001:12ff:0:0:0:0:0:10 // b.dns.br. A 200.189.41.10 // c.dns.br. A 200.192.233.10 // d.dns.br. A 200.219.154.10 // d.dns.br. AAAA 2001:12f8:4:0:0:0:0:10 // e.dns.br. A 200.229.248.10 // e.dns.br. AAAA 2001:12f8:1:0:0:0:0:10 // f.dns.br. A 200.219.159.10 // func readInputFile(inputFilePath string) ([]*model.Domain, error) { // Input file path is necessary when we want to run a performance test, because in this // file we have real DNS authoritative servers if len(inputFilePath) == 0 { return nil, ErrInputFileUndefined } file, err := os.Open(inputFilePath) if err != nil { return nil, err } scanner := bufio.NewScanner(file) domainsInfo := make(map[string]*model.Domain) nameserversInfo := make(map[string]model.Nameserver) // Read line by line for scanner.Scan() { inputParts := strings.Fields(scanner.Text()) if len(inputParts) < 3 { return nil, ErrInputFileInvalidFormat } zone, rrType := strings.ToLower(inputParts[0]), strings.ToUpper(inputParts[1]) if rrType == "NS" { domain := domainsInfo[zone] if domain == nil { domain = &model.Domain{ FQDN: zone, } } domain.Nameservers = append(domain.Nameservers, model.Nameserver{ Host: strings.ToLower(inputParts[2]), }) domainsInfo[zone] = domain } else if rrType == "DS" { domain := domainsInfo[zone] if domain == nil { domain = &model.Domain{ FQDN: zone, } } if len(inputParts) < 6 { return nil, ErrInputFileInvalidFormat } keytag, err := strconv.Atoi(inputParts[2]) if err != nil { return nil, ErrInputFileInvalidFormat } algorithm, err := strconv.Atoi(inputParts[3]) if err != nil { return nil, ErrInputFileInvalidFormat } digestType, err := strconv.Atoi(inputParts[4]) if err != nil { return nil, ErrInputFileInvalidFormat } domain.DSSet = append(domain.DSSet, model.DS{ Keytag: uint16(keytag), Algorithm: model.DSAlgorithm(algorithm), DigestType: model.DSDigestType(digestType), Digest: strings.ToUpper(inputParts[5]), }) domainsInfo[zone] = domain } else if rrType == "A" { nameserver := nameserversInfo[zone] nameserver.Host = strings.ToLower(zone) nameserver.IPv4 = net.ParseIP(inputParts[2]) nameserversInfo[zone] = nameserver } else if rrType == "AAAA" { nameserver := nameserversInfo[zone] nameserver.Host = strings.ToLower(zone) nameserver.IPv6 = net.ParseIP(inputParts[2]) nameserversInfo[zone] = nameserver } else { return nil, ErrInputFileInvalidFormat } } if err := scanner.Err(); err != nil { return nil, err } var domains []*model.Domain for _, domain := range domainsInfo { for index, nameserver := range domain.Nameservers { if nameserverGlue, found := nameserversInfo[nameserver.Host]; found { domain.Nameservers[index] = nameserverGlue } } domains = append(domains, domain) } return domains, nil }
// Send DNS requests to fill a domain object from the information found on the DNS authoritative // nameservers. This is very usefull to make it easier for the user to fill forms with the domain // information. The domain must be already delegated by a registry to this function works, because // it uses a recursive DNS func QueryDomain(fqdn string) (model.Domain, error) { domain := model.Domain{ FQDN: fqdn, } querier := newQuerier( config.ShelterConfig.Scan.UDPMaxSize, time.Duration(config.ShelterConfig.Scan.Timeouts.DialSeconds)*time.Second, time.Duration(config.ShelterConfig.Scan.Timeouts.ReadSeconds)*time.Second, time.Duration(config.ShelterConfig.Scan.Timeouts.WriteSeconds)*time.Second, config.ShelterConfig.Scan.ConnectionRetries, ) resolver := fmt.Sprintf("%s:%d", config.ShelterConfig.Scan.Resolver.Address, config.ShelterConfig.Scan.Resolver.Port, ) var dnsRequestMessage dns.Msg dnsRequestMessage.SetQuestion(fqdn, dns.TypeNS) dnsRequestMessage.RecursionDesired = true // Allow retrieving domain information when there's a DNSSEC problem in the chain-of-trust dnsRequestMessage.CheckingDisabled = true dnsResponseMsg, err := querier.sendDNSRequest(resolver, &dnsRequestMessage) if err != nil { return domain, err } for _, answer := range dnsResponseMsg.Answer { nsRecord, ok := answer.(*dns.NS) if !ok { continue } domain.Nameservers = append(domain.Nameservers, model.Nameserver{ Host: nsRecord.Ns, }) } for index, nameserver := range domain.Nameservers { // Don't need to retrieve glue records if not necessary if !strings.HasSuffix(nameserver.Host, domain.FQDN) { continue } dnsRequestMessage.SetQuestion(nameserver.Host, dns.TypeA) dnsResponseMsg, err = querier.sendDNSRequest(resolver, &dnsRequestMessage) if err != nil { return domain, err } for _, answer := range dnsResponseMsg.Answer { ipv4Record, ok := answer.(*dns.A) if !ok { continue } domain.Nameservers[index].IPv4 = ipv4Record.A } dnsRequestMessage.SetQuestion(nameserver.Host, dns.TypeAAAA) dnsResponseMsg, err = querier.sendDNSRequest(resolver, &dnsRequestMessage) if err != nil { return domain, err } for _, answer := range dnsResponseMsg.Answer { ipv6Record, ok := answer.(*dns.AAAA) if !ok { continue } domain.Nameservers[index].IPv6 = ipv6Record.AAAA } } // We are going to retrieve the DNSKEYs from the user zone, and generate the DS records from it. // This is good if the user wants to use the Shelter project as a easy-to-fill domain registration // form dnsRequestMessage.SetQuestion(fqdn, dns.TypeDNSKEY) dnsResponseMsg, err = querier.sendDNSRequest(resolver, &dnsRequestMessage) if err != nil { return domain, err } for _, answer := range dnsResponseMsg.Answer { dnskeyRecord, ok := answer.(*dns.DNSKEY) if !ok { continue } // Only add DNSKEYs with bit SEP on if (dnskeyRecord.Flags & dns.SEP) == 0 { continue } dsRecord := dnskeyRecord.ToDS(uint8(DefaultDigestType)) domain.DSSet = append(domain.DSSet, model.DS{ Keytag: dsRecord.KeyTag, Algorithm: model.DSAlgorithm(dsRecord.Algorithm), DigestType: model.DSDigestType(dsRecord.DigestType), Digest: dsRecord.Digest, }) } return domain, nil }