示例#1
0
// Check if the revision field avoid data concurrency. Is better to fail than to store the
// wrong state
func domainConcurrency(domainDAO dao.DomainDAO) {
	domain := newDomain()

	// Create domain
	if err := domainDAO.Save(&domain); err != nil {
		utils.Fatalln("Couldn't save domain in database", err)
	}

	domain1, err := domainDAO.FindByFQDN(domain.FQDN)
	if err != nil {
		utils.Fatalln("Couldn't find created domain in database", err)
	}

	domain2, err := domainDAO.FindByFQDN(domain.FQDN)
	if err != nil {
		utils.Fatalln("Couldn't find created domain in database", err)
	}

	if err := domainDAO.Save(&domain1); err != nil {
		utils.Fatalln("Couldn't save domain in database", err)
	}

	if err := domainDAO.Save(&domain2); err == nil {
		utils.Fatalln("Not controlling domain concurrency", nil)
	}

	// Remove domain
	if err := domainDAO.RemoveByFQDN(domain.FQDN); err != nil {
		utils.Fatalln("Error while trying to remove a domain", err)
	}
}
示例#2
0
func domainFilter(domainDAO dao.DomainDAO) {
	numberOfItems := 20

	for i := 0; i < numberOfItems; i++ {
		domain := model.Domain{
			FQDN: fmt.Sprintf("example%d.com.br", i),
		}

		if err := domainDAO.Save(&domain); err != nil {
			utils.Fatalln("Error saving domain in database", err)
		}
	}

	pagination := dao.DomainDAOPagination{
		PageSize: 10,
		Page:     5,
		OrderBy: []dao.DomainDAOSort{
			{
				Field:     dao.DomainDAOOrderByFieldFQDN,
				Direction: dao.DAOOrderByDirectionAscending,
			},
		},
	}

	domains, err := domainDAO.FindAll(&pagination, true, "example1\\.com.*")
	if err != nil {
		utils.Fatalln("Error retrieving domains", err)
	}

	if len(domains) != 1 {
		utils.Fatalln(fmt.Sprintf("Wrong number of domains when there's filter. "+
			"Expected '1' and got '%d'", len(domains)), nil)
	}

	if domains[0].FQDN != "example1.com.br" {
		utils.Fatalln("Wrong domain returned", nil)
	}

	for i := 0; i < numberOfItems; i++ {
		fqdn := fmt.Sprintf("example%d.com.br", i)
		if err := domainDAO.RemoveByFQDN(fqdn); err != nil {
			utils.Fatalln("Error removing domain from database", err)
		}
	}
}
示例#3
0
// FQDN must be unique in the database, today we limit this using an unique index key
func domainUniqueFQDN(domainDAO dao.DomainDAO) {
	domain1 := newDomain()

	// Create domain
	if err := domainDAO.Save(&domain1); err != nil {
		utils.Fatalln("Couldn't save domain in database", err)
	}

	domain2 := newDomain()

	// Create another domain with the same FQDN
	if err := domainDAO.Save(&domain2); err == nil {
		utils.Fatalln("Allowing more than one object with the same FQDN", nil)
	}

	// Remove domain
	if err := domainDAO.RemoveByFQDN(domain1.FQDN); err != nil {
		utils.Fatalln("Error while trying to remove a domain", err)
	}
}
示例#4
0
// Test all phases of the domain life cycle
func domainLifeCycle(domainDAO dao.DomainDAO) {
	domain := newDomain()

	// Create domain
	if err := domainDAO.Save(&domain); err != nil {
		utils.Fatalln("Couldn't save domain in database", err)
	}

	// Search and compare created domain
	if domainRetrieved, err := domainDAO.FindByFQDN(domain.FQDN); err != nil {
		utils.Fatalln("Couldn't find created domain in database", err)

	} else if !utils.CompareDomain(domain, domainRetrieved) {
		utils.Fatalln("Domain created is being persisted wrongly", nil)
	}

	// Update domain
	domain.Owners = []model.Owner{}
	if err := domainDAO.Save(&domain); err != nil {
		utils.Fatalln("Couldn't save domain in database", err)
	}

	// Search and compare updated domain
	if domainRetrieved, err := domainDAO.FindByFQDN(domain.FQDN); err != nil {
		utils.Fatalln("Couldn't find updated domain in database", err)

	} else if !utils.CompareDomain(domain, domainRetrieved) {
		utils.Fatalln("Domain updated is being persisted wrongly", nil)
	}

	// Remove domain
	if err := domainDAO.RemoveByFQDN(domain.FQDN); err != nil {
		utils.Fatalln("Error while trying to remove a domain", err)
	}

	// Check removal
	if _, err := domainDAO.FindByFQDN(domain.FQDN); err == nil {
		utils.Fatalln("Domain was not removed from database", nil)
	}
}
示例#5
0
func domainWithNoErrors(config ScanInjectorTestConfigFile, domainDAO dao.DomainDAO) {
	domain := newDomain()

	// Set all nameservers as configured correctly and the last check as now, this domain is
	// unlikely to be selected
	for index, _ := range domain.Nameservers {
		domain.Nameservers[index].LastCheckAt = time.Now()
		domain.Nameservers[index].LastStatus = model.NameserverStatusOK
	}

	// Set all DS records as configured correctly and the last check as now, this domain is
	// unlikely to be selected
	for index, _ := range domain.DSSet {
		domain.DSSet[index].LastCheckAt = time.Now()
		domain.DSSet[index].LastStatus = model.DSStatusOK
	}

	if err := domainDAO.Save(&domain); err != nil {
		utils.Fatalln("Error saving domain for scan scenario", err)
	}

	model.StartNewScan()
	if domains := runScan(config, domainDAO); len(domains) > 0 {
		utils.Fatalln(fmt.Sprintf("Selected a domain configured correctly for the scan. "+
			"Expected 0 got %d", len(domains)), nil)
	}

	currentScan := model.GetCurrentScan()
	if currentScan.Status != model.ScanStatusRunning {
		utils.Fatalln("Not changing the scan info status for domain with no errors", nil)
	}

	if currentScan.DomainsToBeScanned > 0 {
		utils.Fatalln("Not counting the domains to be scanned for domain with no errors", nil)
	}

	if err := domainDAO.RemoveByFQDN(domain.FQDN); err != nil {
		utils.Fatalln("Error removing domain", err)
	}
}
示例#6
0
func domainWithDNSErrors(config ScanInjectorTestConfigFile, domainDAO dao.DomainDAO) {
	domain := newDomain()

	// Set all nameservers with error and the last check equal of the error check interval,
	// this will force the domain to be checked
	for index, _ := range domain.Nameservers {
		maxErrorHours := config.Scan.VerificationIntervals.MaxErrorDays * 24
		lessThreeDays, _ := time.ParseDuration("-" + strconv.Itoa(maxErrorHours) + "h")

		domain.Nameservers[index].LastCheckAt = time.Now().Add(lessThreeDays)
		domain.Nameservers[index].LastStatus = model.NameserverStatusServerFailure
	}

	if err := domainDAO.Save(&domain); err != nil {
		utils.Fatalln("Error saving domain for scan scenario", err)
	}

	model.StartNewScan()
	if domains := runScan(config, domainDAO); len(domains) != 1 {
		utils.Fatalln(fmt.Sprintf("Couldn't load a domain with DNS errors for scan. "+
			"Expected 1 got %d", len(domains)), nil)
	}

	currentScan := model.GetCurrentScan()
	if currentScan.Status != model.ScanStatusRunning {
		utils.Fatalln("Not changing the scan info status with DNS errors", nil)
	}

	if currentScan.DomainsToBeScanned != 1 {
		utils.Fatalln("Not counting the domains to be scanned with DNS errors", nil)
	}

	if err := domainDAO.RemoveByFQDN(domain.FQDN); err != nil {
		utils.Fatalln("Error removing domain", err)
	}
}
示例#7
0
// Verify if the method that choose the domains that needs to be verified is correct
func domainsNotification(domainDAO dao.DomainDAO) {
	numberOfItemsToBeVerified := 1000
	numberOfItemsToDontBeVerified := 1000
	nameserverErrorAlertDays := 7
	nameserverTimeoutAlertDays := 30
	dsErrorAlertDays := 1
	dsTimeoutAlertDays := 7
	maxExpirationAlertDays := 5

	data := []struct {
		name                      string
		numberOfItems             int
		nameserverTimeoutLastOKAt time.Time
		nameserverErrorLastOKAt   time.Time
		dsTimeoutLastOkAt         time.Time
		dsErrorLastOkAt           time.Time
		dsExpiresAt               time.Time
	}{
		{
			name:                      "shouldbenotified",
			numberOfItems:             numberOfItemsToBeVerified,
			nameserverTimeoutLastOKAt: time.Now().Add(time.Duration(-nameserverTimeoutAlertDays*24) * time.Hour),
			nameserverErrorLastOKAt:   time.Now().Add(time.Duration(-nameserverErrorAlertDays*24) * time.Hour),
			dsTimeoutLastOkAt:         time.Now().Add(time.Duration(-dsTimeoutAlertDays*24) * time.Hour),
			dsErrorLastOkAt:           time.Now().Add(time.Duration(-dsErrorAlertDays*24) * time.Hour),
			dsExpiresAt:               time.Now().Add(time.Duration((maxExpirationAlertDays)*24) * time.Hour),
		},
		{
			name:                      "shouldnotbenotified",
			numberOfItems:             numberOfItemsToDontBeVerified,
			nameserverTimeoutLastOKAt: time.Now().Add(time.Duration((-nameserverTimeoutAlertDays+1)*24) * time.Hour),
			nameserverErrorLastOKAt:   time.Now().Add(time.Duration((-nameserverErrorAlertDays+1)*24) * time.Hour),
			dsTimeoutLastOkAt:         time.Now().Add(time.Duration((-dsTimeoutAlertDays+1)*24) * time.Hour),
			dsErrorLastOkAt:           time.Now().Add(time.Duration((-dsErrorAlertDays+1)*24) * time.Hour),
			dsExpiresAt:               time.Now().Add(time.Duration((maxExpirationAlertDays+1)*24) * time.Hour),
		},
	}

	for _, item := range data {
		for i := 0; i < item.numberOfItems/5; i++ {
			domain := model.Domain{
				FQDN: fmt.Sprintf("%s%d.com.br", item.name, i),
				Nameservers: []model.Nameserver{
					{
						LastStatus: model.NameserverStatusTimeout,
						LastOKAt:   item.nameserverTimeoutLastOKAt,
					},
				},
			}

			if err := domainDAO.Save(&domain); err != nil {
				utils.Fatalln("Error saving domain in database", err)
			}
		}

		for i := item.numberOfItems / 5; i < item.numberOfItems/5*2; i++ {
			domain := model.Domain{
				FQDN: fmt.Sprintf("%s%d.com.br", item.name, i),
				Nameservers: []model.Nameserver{
					{
						LastStatus: model.NameserverStatusNoAuthority,
						LastOKAt:   item.nameserverErrorLastOKAt,
					},
				},
			}

			if err := domainDAO.Save(&domain); err != nil {
				utils.Fatalln("Error saving domain in database", err)
			}
		}

		for i := item.numberOfItems / 5 * 2; i < item.numberOfItems/5*3; i++ {
			domain := model.Domain{
				FQDN: fmt.Sprintf("%s%d.com.br", item.name, i),
				DSSet: []model.DS{
					{
						LastStatus: model.DSStatusTimeout,
						LastOKAt:   item.dsTimeoutLastOkAt,
						ExpiresAt:  time.Now().Add(time.Duration((maxExpirationAlertDays+1)*24) * time.Hour),
					},
				},
			}

			if err := domainDAO.Save(&domain); err != nil {
				utils.Fatalln("Error saving domain in database", err)
			}
		}

		for i := item.numberOfItems / 5 * 3; i < item.numberOfItems/5*4; i++ {
			domain := model.Domain{
				FQDN: fmt.Sprintf("%s%d.com.br", item.name, i),
				DSSet: []model.DS{
					{
						LastStatus: model.DSStatusExpiredSignature,
						LastOKAt:   item.dsErrorLastOkAt,
						ExpiresAt:  time.Now().Add(time.Duration((maxExpirationAlertDays+1)*24) * time.Hour),
					},
				},
			}

			if err := domainDAO.Save(&domain); err != nil {
				utils.Fatalln("Error saving domain in database", err)
			}
		}

		for i := item.numberOfItems / 5 * 4; i < item.numberOfItems; i++ {
			domain := model.Domain{
				FQDN: fmt.Sprintf("%s%d.com.br", item.name, i),
				DSSet: []model.DS{
					{
						LastStatus: model.DSStatusOK,
						LastOKAt:   time.Now(),
						ExpiresAt:  item.dsExpiresAt,
					},
				},
			}

			if err := domainDAO.Save(&domain); err != nil {
				utils.Fatalln("Error saving domain in database", err)
			}
		}
	}

	domainChannel, err := domainDAO.FindAllAsyncToBeNotified(
		nameserverErrorAlertDays,
		nameserverTimeoutAlertDays,
		dsErrorAlertDays,
		dsTimeoutAlertDays,
		maxExpirationAlertDays,
	)

	if err != nil {
		utils.Fatalln("Error retrieving domains to be notified", err)
	}

	var domains []*model.Domain
	for {
		domainResult := <-domainChannel

		if domainResult.Error != nil {
			utils.Fatalln("Error retrieving domain to be notified", domainResult.Error)
		}

		if domainResult.Error != nil || domainResult.Domain == nil {
			break
		}

		domains = append(domains, domainResult.Domain)
	}

	if len(domains) != numberOfItemsToBeVerified {
		utils.Fatalln(fmt.Sprintf("Did not select all the domains ready for notification. "+
			"Expected %d and got %d", numberOfItemsToBeVerified, len(domains)), nil)
	}

	for _, item := range data {
		for i := 0; i < item.numberOfItems; i++ {
			fqdn := fmt.Sprintf("%s%d.com.br", item.name, i)
			if err := domainDAO.RemoveByFQDN(fqdn); err != nil {
				utils.Fatalln("Error removing domain from database", err)
			}
		}
	}
}
示例#8
0
func domainsPagination(domainDAO dao.DomainDAO) {
	numberOfItems := 1000

	for i := 0; i < numberOfItems; i++ {
		domain := model.Domain{
			FQDN: fmt.Sprintf("example%d.com.br", i),
		}

		if err := domainDAO.Save(&domain); err != nil {
			utils.Fatalln("Error saving domain in database", err)
		}
	}

	pagination := dao.DomainDAOPagination{
		PageSize: 10,
		Page:     5,
		OrderBy: []dao.DomainDAOSort{
			{
				Field:     dao.DomainDAOOrderByFieldFQDN,
				Direction: dao.DAOOrderByDirectionAscending,
			},
		},
	}

	domains, err := domainDAO.FindAll(&pagination, true, "")
	if err != nil {
		utils.Fatalln("Error retrieving domains", err)
	}

	if pagination.NumberOfItems != numberOfItems {
		utils.Errorln("Number of items not calculated correctly", nil)
	}

	if pagination.NumberOfPages != numberOfItems/pagination.PageSize {
		utils.Errorln("Number of pages not calculated correctly", nil)
	}

	if len(domains) != pagination.PageSize {
		utils.Errorln("Number of domains not following page size", nil)
	}

	pagination = dao.DomainDAOPagination{
		PageSize: 10000,
		Page:     1,
		OrderBy: []dao.DomainDAOSort{
			{
				Field:     dao.DomainDAOOrderByFieldFQDN,
				Direction: dao.DAOOrderByDirectionAscending,
			},
		},
	}

	domains, err = domainDAO.FindAll(&pagination, true, "")
	if err != nil {
		utils.Fatalln("Error retrieving domains", err)
	}

	if pagination.NumberOfPages != 1 {
		utils.Fatalln("Calculating wrong number of pages when there's only one page", nil)
	}

	for i := 0; i < numberOfItems; i++ {
		fqdn := fmt.Sprintf("example%d.com.br", i)
		if err := domainDAO.RemoveByFQDN(fqdn); err != nil {
			utils.Fatalln("Error removing domain from database", err)
		}
	}
}
示例#9
0
func domainWithErrors(config ScanCollectorTestConfigFile, database *mgo.Database) {
	domainsToSave := make(chan *model.Domain, config.Scan.DomainsBufferSize)
	domainsToSave <- &model.Domain{
		FQDN: "br.",
		Nameservers: []model.Nameserver{
			{
				Host:       "ns1.br",
				IPv4:       net.ParseIP("127.0.0.1"),
				LastStatus: model.NameserverStatusTimeout,
			},
		},
		DSSet: []model.DS{
			{
				Keytag:     1234,
				Algorithm:  model.DSAlgorithmRSASHA1NSEC3,
				DigestType: model.DSDigestTypeSHA1,
				Digest:     "EAA0978F38879DB70A53F9FF1ACF21D046A98B5C",
				LastStatus: model.DSStatusExpiredSignature,
			},
		},
	}
	domainsToSave <- nil

	model.StartNewScan()
	runScan(config, database, domainsToSave)

	domainDAO := dao.DomainDAO{
		Database: database,
	}

	domain, err := domainDAO.FindByFQDN("br.")
	if err != nil {
		utils.Fatalln("Error loading domain with problems", err)
	}

	if len(domain.Nameservers) == 0 {
		utils.Fatalln("Error saving nameservers", nil)
	}

	if domain.Nameservers[0].LastStatus != model.NameserverStatusTimeout {
		utils.Fatalln("Error setting status in the nameserver", nil)
	}

	if len(domain.DSSet) == 0 {
		utils.Fatalln("Error saving the DS set", nil)
	}

	if domain.DSSet[0].LastStatus != model.DSStatusExpiredSignature {
		utils.Fatalln("Error setting status in the DS", nil)
	}

	if err := domainDAO.RemoveByFQDN("br."); err != nil {
		utils.Fatalln("Error removing test domain", err)
	}

	currentScan := model.GetCurrentScan()
	if currentScan.DomainsScanned != 1 || currentScan.DomainsWithDNSSECScanned != 1 {
		utils.Fatalln("Not counting domains for scan progress when there're errors", nil)
	}

	if currentScan.NameserverStatistics[model.NameserverStatusToString(model.NameserverStatusTimeout)] != 1 ||
		currentScan.DSStatistics[model.DSStatusToString(model.DSStatusExpiredSignature)] != 1 {
		utils.Fatalln("Not counting statistics properly when there're errors", nil)
	}
}
示例#10
0
func simpleNotification(domainDAO dao.DomainDAO, templateName string,
	messageChannel chan *mail.Message, errorChannel chan error) {

	generateAndSaveDomain("example.com.br.", domainDAO, templateName)

	notification.TemplateExtension = ""
	if err := notification.LoadTemplates(); err != nil {
		utils.Fatalln("Error loading templates", err)
	}

	notification.Notify()

	timeout := make(chan bool, 1)
	go func() {
		time.Sleep(5 * time.Second)
		timeout <- true
	}()

	select {
	case message := <-messageChannel:
		if message.Header.Get("From") != "*****@*****.**" {
			utils.Fatalln(fmt.Sprintf("E-mail from header is different. Expected "+
				"[email protected] but found %s", message.Header.Get("From")), nil)
		}

		if message.Header.Get("To") != "*****@*****.**" {
			utils.Fatalln("E-mail to header is different", nil)
		}

		if message.Header.Get("Subject") != "=?UTF-8?B?TWlzY29uZmlndXJhdGlvbiBvbiBkb21haW4gZXhhbXBsZS5jb20uYnIu?=" {
			utils.Fatalln("E-mail subject header is different", nil)
		}

		body, err := ioutil.ReadAll(message.Body)
		if err != nil {
			utils.Fatalln("Error reading e-mail body", err)
		}

		expectedBody := "Dear Sir/Madam,\r\n" +
			"\r\n" +
			"During our periodically domain verification, a configuration problem was detected with the\r\n" +
			"domain example.com.br..\r\n" +
			"\r\n" +
			"  * Nameserver ns1.example.com.br. got an internal error while receiving the DNS request.\r\n" +
			"    Please check the DNS server log to detect and solve the problem.\r\n" +
			"\r\n" +
			"Best regards,\r\n" +
			"LACTLD\r\n" +
			".\r\n"

		if string(body) != expectedBody {
			utils.Fatalln(fmt.Sprintf("E-mail body is different from what we expected. "+
				"Expected [%s], but found [%s]", expectedBody, body), nil)
		}

	case err := <-errorChannel:
		utils.Fatalln("Error receiving message", err)

	case <-timeout:
		utils.Fatalln("No mail sent", nil)
	}

	if err := domainDAO.RemoveByFQDN("example.com.br."); err != nil {
		utils.Fatalln("Error removing domain", err)
	}
}
示例#11
0
func brDomainWithoutDNSSEC(domainDAO dao.DomainDAO) {
	domain := model.Domain{
		FQDN: "br.",
		Nameservers: []model.Nameserver{
			{
				Host: "a.dns.br.",
				IPv4: net.ParseIP("200.160.0.10"),
				IPv6: net.ParseIP("2001:12ff::10"),
			},
			{
				Host: "b.dns.br.",
				IPv4: net.ParseIP("200.189.41.10"),
			},
			{
				Host: "c.dns.br.",
				IPv4: net.ParseIP("200.192.233.10"),
			},
			{
				Host: "d.dns.br.",
				IPv4: net.ParseIP("200.219.154.10"),
				IPv6: net.ParseIP("2001:12f8:4::10"),
			},
			{
				Host: "f.dns.br.",
				IPv4: net.ParseIP("200.219.159.10"),
			},
		},

		// We are going to add the current DNSKEYs from .br but we are not going to check it.
		// This is because there's a strange case that when it found a problem on a DS (such
		// as bit SEP) it does not check other nameservers
		DSSet: []model.DS{
			{
				Keytag:     41674,
				Algorithm:  model.DSAlgorithmRSASHA1,
				DigestType: model.DSDigestTypeSHA256,
				Digest:     "6ec74914376b4f383ede3840088ae1d7bf13a19bfc51465cc2da57618889416a",
			},
			{
				Keytag:     57207,
				Algorithm:  model.DSAlgorithmRSASHA1,
				DigestType: model.DSDigestTypeSHA256,
				Digest:     "d46f059860d31a0965f925ac6ff97ed0975f33a14e2d01ec5ab5dd543624d307",
			},
		},
	}

	var err error

	if err = domainDAO.Save(&domain); err != nil {
		utils.Fatalln("Error saving the domain", err)
	}

	scan.ScanDomains()

	domain, err = domainDAO.FindByFQDN(domain.FQDN)
	if err != nil {
		utils.Fatalln("Didn't find scanned domain", err)
	}

	for _, nameserver := range domain.Nameservers {
		if nameserver.LastStatus != model.NameserverStatusOK {
			utils.Fatalln(fmt.Sprintf("Fail to validate a supposedly well configured nameserver '%s'. Found status: %s",
				nameserver.Host, model.NameserverStatusToString(nameserver.LastStatus)), nil)
		}
	}

	if err := domainDAO.RemoveByFQDN(domain.FQDN); err != nil {
		utils.Fatalln(fmt.Sprintf("Error removing domain %s", domain.FQDN), err)
	}
}
示例#12
0
func domainWithNoErrors(domainDAO dao.DomainDAO) {
	domain, dnskey, rrsig, lastCheckAt, lastOKAt := generateSignAndSaveDomain("br.", domainDAO)

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

		if dnsRequestMessage.Question[0].Qtype == dns.TypeSOA {
			dnsResponseMessage := &dns.Msg{
				MsgHdr: dns.MsgHdr{
					Authoritative: true,
				},
				Question: dnsRequestMessage.Question,
				Answer: []dns.RR{
					&dns.SOA{
						Hdr: dns.RR_Header{
							Name:   "br.",
							Rrtype: dns.TypeSOA,
							Class:  dns.ClassINET,
							Ttl:    86400,
						},
						Ns:      "ns1.br.",
						Mbox:    "rafael.justo.net.br.",
						Serial:  2013112600,
						Refresh: 86400,
						Retry:   86400,
						Expire:  86400,
						Minttl:  900,
					},
				},
			}
			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)
		}
	})

	scan.ScanDomains()

	domain, err := domainDAO.FindByFQDN(domain.FQDN)
	if err != nil {
		utils.Fatalln("Didn't find scanned domain", err)
	}

	for _, nameserver := range domain.Nameservers {
		if nameserver.LastStatus != model.NameserverStatusOK {
			utils.Fatalln(fmt.Sprintf("Fail to validate a supposedly well configured nameserver '%s'. Found status: %s",
				nameserver.Host, model.NameserverStatusToString(nameserver.LastStatus)), nil)
		}

		if nameserver.LastCheckAt.Before(lastCheckAt) ||
			nameserver.LastCheckAt.Equal(lastCheckAt) {
			utils.Fatalln(fmt.Sprintf("Last check date was not updated in nameserver '%s'",
				nameserver.Host), nil)
		}

		if nameserver.LastOKAt.Before(lastOKAt) || nameserver.LastOKAt.Equal(lastOKAt) {
			utils.Fatalln(fmt.Sprintf("Last OK date was not updated in nameserver '%s'",
				nameserver.Host), nil)
		}
	}

	for _, ds := range domain.DSSet {
		if ds.LastStatus != model.DSStatusOK {
			utils.Fatalln(fmt.Sprintf("Fail to validate a supposedly well configured DS %d. "+
				"Found status: %s", ds.Keytag, model.DSStatusToString(ds.LastStatus)), nil)
		}

		if ds.LastCheckAt.Before(lastCheckAt) || ds.LastCheckAt.Equal(lastCheckAt) {
			utils.Fatalln(fmt.Sprintf("Last check date was not updated in DS %d",
				ds.Keytag), nil)
		}

		if ds.LastOKAt.Before(lastOKAt) || ds.LastOKAt.Equal(lastOKAt) {
			utils.Fatalln(fmt.Sprintf("Last OK date was not updated in DS %d",
				ds.Keytag), nil)
		}
	}

	if err := domainDAO.RemoveByFQDN(domain.FQDN); err != nil {
		utils.Fatalln(fmt.Sprintf("Error removing domain %s", domain.FQDN), err)
	}
}
func scanPersistedDomain(domainDAO dao.DomainDAO) {
	dns.HandleFunc("example.com.br.", func(w dns.ResponseWriter, dnsRequestMessage *dns.Msg) {
		defer w.Close()

		dnsResponseMessage := &dns.Msg{
			MsgHdr: dns.MsgHdr{
				Authoritative: true,
			},
			Question: dnsRequestMessage.Question,
			Answer: []dns.RR{
				&dns.SOA{
					Hdr: dns.RR_Header{
						Name:   "example.com.br.",
						Rrtype: dns.TypeSOA,
						Class:  dns.ClassINET,
						Ttl:    86400,
					},
					Ns:      "ns1.example.com.br.",
					Mbox:    "rafael.justo.net.br.",
					Serial:  2013112600,
					Refresh: 86400,
					Retry:   86400,
					Expire:  86400,
					Minttl:  900,
				},
			},
		}

		dnsResponseMessage.SetReply(dnsRequestMessage)
		w.WriteMsg(dnsResponseMessage)
	})

	mux := handy.NewHandy()

	h := new(handler.DomainVerificationHandler)
	mux.Handle("/domain/{fqdn}/verification", func() handy.Handler {
		return h
	})

	requestContent := `{
      "Nameservers": [
        { "Host": "ns1.example.com.br.", "ipv4": "127.0.0.1" },
        { "Host": "ns2.example.com.br.", "ipv4": "127.0.0.1" }
      ]
    }`

	domain := model.Domain{
		FQDN: "example.com.br.",
		Nameservers: []model.Nameserver{
			{
				Host: "ns1.example.com.br.",
				IPv4: net.ParseIP("127.0.0.1"),
			},
			{
				Host: "ns2.example.com.br.",
				IPv4: net.ParseIP("127.0.0.1"),
			},
		},
	}

	if err := domainDAO.Save(&domain); err != nil {
		utils.Fatalln("Error saving domain", err)
	}

	r, err := http.NewRequest("PUT", "/domain/example.com.br./verification",
		strings.NewReader(requestContent))
	if err != nil {
		utils.Fatalln("Error creating the HTTP request", err)
	}
	utils.BuildHTTPHeader(r, []byte(requestContent))

	w := httptest.NewRecorder()
	mux.ServeHTTP(w, r)

	responseContent, err := ioutil.ReadAll(w.Body)
	if err != nil {
		utils.Fatalln("Error reading response body", err)
	}

	if w.Code != http.StatusOK {
		utils.Fatalln(fmt.Sprintf("Error scanning domain. "+
			"Expected %d and got %d", http.StatusOK, w.Code),
			errors.New(string(responseContent)))
	}

	domain, err = domainDAO.FindByFQDN(domain.FQDN)
	if err != nil {
		utils.Fatalln("Error retrieving the domain", err)
	}

	if len(domain.Nameservers) != 2 ||
		domain.Nameservers[0].LastStatus != model.NameserverStatusOK ||
		domain.Nameservers[1].LastStatus != model.NameserverStatusOK {

		utils.Fatalln("Not updating domain on a scan", nil)
	}

	// Now we are going to test when the database domain is different from the scanned domain

	if err := domainDAO.RemoveByFQDN(domain.FQDN); err != nil {
		utils.Fatalln("Error removing domain", err)
	}

	domain = model.Domain{
		FQDN: "example.com.br.",
		Nameservers: []model.Nameserver{
			{
				Host: "ns1.example.com.br.",
				IPv4: net.ParseIP("127.0.0.1"),
			},
			{
				Host: "ns3.example.com.br.",
				IPv4: net.ParseIP("127.0.0.1"),
			},
		},
	}

	if err := domainDAO.Save(&domain); err != nil {
		utils.Fatalln("Error saving domain", err)
	}

	mux.ServeHTTP(w, r)

	responseContent, err = ioutil.ReadAll(w.Body)
	if err != nil {
		utils.Fatalln("Error reading response body", err)
	}

	if w.Code != http.StatusOK {
		utils.Fatalln(fmt.Sprintf("Error scanning domain. "+
			"Expected %d and got %d", http.StatusOK, w.Code),
			errors.New(string(responseContent)))
	}

	domain, err = domainDAO.FindByFQDN(domain.FQDN)
	if err != nil {
		utils.Fatalln("Error retrieving the domain", err)
	}

	if len(domain.Nameservers) != 2 ||
		domain.Nameservers[0].LastStatus != model.NameserverStatusNotChecked ||
		domain.Nameservers[1].LastStatus != model.NameserverStatusNotChecked {

		utils.Fatalln("Updating domain on a scan when it shouldn't", nil)
	}
}