func createCurrentScan() { // We are not going to call the function FinishAnalyzingDomainForScan because it will reset the // current scan information model.StartNewScan() model.LoadedDomainForScan() model.LoadedDomainForScan() model.LoadedDomainForScan() model.FinishAnalyzingDomainForScan(false) model.LoadedDomainForScan() model.LoadedDomainForScan() model.FinishLoadingDomainsForScan() model.FinishAnalyzingDomainForScan(false) model.FinishAnalyzingDomainForScan(false) model.FinishAnalyzingDomainForScan(true) }
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) } }
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) } }
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) } }
// Function responsible for running the domain scan system, checking the configuration of each // domain in the database according to an algorithm. This method is synchronous and will return only // after the scan proccess is done func ScanDomains() { defer func() { // Something went really wrong while scanning the domains. Log the error stacktrace // and move out if r := recover(); r != nil { const size = 64 << 10 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] log.Printf("Panic detected while scanning domains. Details: %v\n%s", r, buf) } }() log.Info("Start scan job") defer func() { log.Info("End scan job") }() log.Debugf("Initializing database with the parameters: URIS - %v | Name - %s | Auth - %t | Username - %s", config.ShelterConfig.Database.URIs, config.ShelterConfig.Database.Name, config.ShelterConfig.Database.Auth.Enabled, config.ShelterConfig.Database.Auth.Username, ) database, databaseSession, err := mongodb.Open( config.ShelterConfig.Database.URIs, config.ShelterConfig.Database.Name, config.ShelterConfig.Database.Auth.Enabled, config.ShelterConfig.Database.Auth.Username, config.ShelterConfig.Database.Auth.Password, ) if err != nil { log.Println("Error while initializing database. Details:", err) return } defer databaseSession.Close() injector := NewInjector( database, config.ShelterConfig.Scan.DomainsBufferSize, config.ShelterConfig.Scan.VerificationIntervals.MaxOKDays, config.ShelterConfig.Scan.VerificationIntervals.MaxErrorDays, config.ShelterConfig.Scan.VerificationIntervals.MaxExpirationAlertDays, ) querierDispatcher := NewQuerierDispatcher( config.ShelterConfig.Scan.NumberOfQueriers, config.ShelterConfig.Scan.DomainsBufferSize, 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, ) collector := NewCollector( database, config.ShelterConfig.Scan.SaveAtOnce, ) // Create a new scan information model.StartNewScan() var scanGroup sync.WaitGroup errorsChannel := make(chan error, config.ShelterConfig.Scan.ErrorsBufferSize) domainsToQueryChannel := injector.Start(&scanGroup, errorsChannel) domainsToSaveChannel := querierDispatcher.Start(&scanGroup, domainsToQueryChannel) collector.Start(&scanGroup, domainsToSaveChannel, errorsChannel) // Keep track of errors for the scan information structure errorDetected := false go func() { for { select { case err := <-errorsChannel: // Detect the poison pill to finish the error listener go routine. This poison // pill should be sent after all parts of the scan are done and we are sure that // we don't have any error to log anymore if err == nil { return } else { errorDetected = true log.Println("Error detected while executing the scan. Details:", err) } } } }() // Wait for all parts of the scan to finish their job scanGroup.Wait() // Finish the error listener sending a poison pill errorsChannel <- nil scanDAO := dao.ScanDAO{ Database: database, } // Save the scan information for future reports if err := model.FinishAndSaveScan(errorDetected, scanDAO.Save); err != nil { log.Println("Error while saving scan information. Details:", err) } }