コード例 #1
0
ファイル: ds.go プロジェクト: rafaeljusto/shelter
// 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
}
コード例 #2
0
ファイル: scan.go プロジェクト: rafaeljusto/shelter
func domainQuery() {
	_, dnskey, rrsig, _, _ := generateAndSignDomain("example.com.br.")

	dns.HandleFunc("example.com.br.", func(w dns.ResponseWriter, dnsRequestMessage *dns.Msg) {
		defer w.Close()

		if dnsRequestMessage.Question[0].Qtype == dns.TypeNS {
			dnsResponseMessage := &dns.Msg{
				MsgHdr:   dns.MsgHdr{},
				Question: dnsRequestMessage.Question,
				Answer: []dns.RR{
					&dns.NS{
						Hdr: dns.RR_Header{
							Name:   "example.com.br.",
							Rrtype: dns.TypeNS,
							Class:  dns.ClassINET,
							Ttl:    86400,
						},
						Ns: "ns1.example.com.br.",
					},
				},
			}
			dnsResponseMessage.SetReply(dnsRequestMessage)
			w.WriteMsg(dnsResponseMessage)

		} else if dnsRequestMessage.Question[0].Qtype == dns.TypeDNSKEY {
			dnsResponseMessage := &dns.Msg{
				MsgHdr: dns.MsgHdr{
					Authoritative: true,
				},
				Question: dnsRequestMessage.Question,
				Answer: []dns.RR{
					dnskey,
					rrsig,
				},
			}
			dnsResponseMessage.SetReply(dnsRequestMessage)
			w.WriteMsg(dnsResponseMessage)
		}
	})

	dns.HandleFunc("ns1.example.com.br.", func(w dns.ResponseWriter, dnsRequestMessage *dns.Msg) {
		defer w.Close()

		if dnsRequestMessage.Question[0].Qtype == dns.TypeA {
			dnsResponseMessage := &dns.Msg{
				MsgHdr: dns.MsgHdr{
					Authoritative: true,
				},
				Question: dnsRequestMessage.Question,
				Answer: []dns.RR{
					&dns.A{
						Hdr: dns.RR_Header{
							Name:   "ns1.example.com.br.",
							Rrtype: dns.TypeA,
							Class:  dns.ClassINET,
							Ttl:    86400,
						},
						A: net.ParseIP("127.0.0.1"),
					},
				},
			}
			dnsResponseMessage.SetReply(dnsRequestMessage)
			w.WriteMsg(dnsResponseMessage)

		} else if dnsRequestMessage.Question[0].Qtype == dns.TypeAAAA {
			dnsResponseMessage := &dns.Msg{
				MsgHdr: dns.MsgHdr{
					Authoritative: true,
				},
				Question: dnsRequestMessage.Question,
				Answer: []dns.RR{
					&dns.AAAA{
						Hdr: dns.RR_Header{
							Name:   "ns1.example.com.br.",
							Rrtype: dns.TypeAAAA,
							Class:  dns.ClassINET,
							Ttl:    86400,
						},
						AAAA: net.ParseIP("::1"),
					},
				},
			}
			dnsResponseMessage.SetReply(dnsRequestMessage)
			w.WriteMsg(dnsResponseMessage)
		}
	})

	domain, err := scan.QueryDomain("example.com.br.")
	if err != nil {
		utils.Fatalln("Error resolving a domain", err)
	}

	if domain.FQDN != "example.com.br." {
		utils.Fatalln("Did not set FQDN properly in domain query", nil)
	}

	if len(domain.Nameservers) != 1 {
		println(len(domain.Nameservers))
		utils.Fatalln("Did not return the desired nameservers in domain query", nil)
	}

	if domain.Nameservers[0].Host != "ns1.example.com.br." {
		utils.Fatalln("Did not set a valid host in domain query", nil)
	}

	if domain.Nameservers[0].IPv4.String() != "127.0.0.1" {
		utils.Fatalln("Did not set a valid IPv4 in domain query", nil)
	}

	if domain.Nameservers[0].IPv6.String() != "::1" {
		utils.Fatalln("Did not set a valid IPv6 in domain query", nil)
	}

	if len(domain.DSSet) != 1 {
		utils.Fatalln("Did not return the desired DS set in domain query", nil)
	}

	if domain.DSSet[0].Keytag != dnskey.KeyTag() {
		utils.Fatalln("Did not set a valid keytag in domain query", nil)
	}

	if domain.DSSet[0].Algorithm != model.DSAlgorithm(dnskey.Algorithm) {
		utils.Fatalln("Did not set a valid algorithm in domain query", nil)
	}
}
コード例 #3
0
ファイル: scan_querier.go プロジェクト: rafaeljusto/shelter
// 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
}
コード例 #4
0
ファイル: scan.go プロジェクト: rafaeljusto/shelter
// 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
}