// 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) } }
func (i *Domain) Before(w http.ResponseWriter, r *http.Request) { domainDAO := dao.DomainDAO{ Database: i.domainHandler.GetDatabase(), } domain, err := domainDAO.FindByFQDN(i.domainHandler.GetFQDN()) // For PUT method if the domain does not exist yet thats alright because we will create // it if r.Method != "PUT" && err != nil { w.WriteHeader(http.StatusNotFound) return } i.domainHandler.SetDomain(domain) }
// 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) } }
func calculateDomainDAODurations(domainDAO dao.DomainDAO, numberOfItems int) (totalDuration, insertDuration, queryDuration, removeDuration time.Duration) { beginTimer := time.Now() sectionTimer := beginTimer // Build array to create many at once var domains []*model.Domain for i := 0; i < numberOfItems; i++ { domain := model.Domain{ FQDN: fmt.Sprintf("test%d.com.br", i), } domains = append(domains, &domain) } errorInDomainsCreation := false domainResults := domainDAO.SaveMany(domains) // Check if there was any error while creating them for _, domainResult := range domainResults { if domainResult.Error != nil { errorInDomainsCreation = true utils.Errorln(fmt.Sprintf("Couldn't save domain %s in database during the performance test", domainResult.Domain.FQDN), domainResult.Error) } } if errorInDomainsCreation { utils.Fatalln("Due to errors in domain creation, the performance test will be aborted", nil) } insertDuration = time.Since(sectionTimer) sectionTimer = time.Now() // Try to find domains from different parts of the whole range to check indexes queryRanges := numberOfItems / 4 fqdn1 := fmt.Sprintf("test%d.com.br", queryRanges) fqdn2 := fmt.Sprintf("test%d.com.br", queryRanges*2) fqdn3 := fmt.Sprintf("test%d.com.br", queryRanges*3) if _, err := domainDAO.FindByFQDN(fqdn1); err != nil { utils.Fatalln(fmt.Sprintf("Couldn't find domain %s in database during "+ "the performance test", fqdn1), err) } if _, err := domainDAO.FindByFQDN(fqdn2); err != nil { utils.Fatalln(fmt.Sprintf("Couldn't find domain %s in database during "+ "the performance test", fqdn2), err) } if _, err := domainDAO.FindByFQDN(fqdn3); err != nil { utils.Fatalln(fmt.Sprintf("Couldn't find domain %s in database during "+ "the performance test", fqdn3), err) } queryDuration = time.Since(sectionTimer) sectionTimer = time.Now() errorInDomainsRemoval := false domainResults = domainDAO.RemoveMany(domains) // Check if there was any error while removing them for _, domainResult := range domainResults { if domainResult.Error != nil { errorInDomainsRemoval = true utils.Errorln(fmt.Sprintf("Error while trying to remove a domain %s during the performance test", domainResult.Domain.FQDN), domainResult.Error) } } if errorInDomainsRemoval { utils.Fatalln("Due to errors in domain removal, the performance test will be aborted", nil) } removeDuration = time.Since(sectionTimer) totalDuration = time.Since(beginTimer) return }
// Test all phases from a domain lyfe cycle, but now working with a group of domains func domainsLifeCycle(domainDAO dao.DomainDAO) { domains := newDomains() // Create domains domainResults := domainDAO.SaveMany(domains) for _, domainResult := range domainResults { if domainResult.Error != nil { utils.Fatalln(fmt.Sprintf("Couldn't save domain %s in database", domainResult.Domain.FQDN), domainResult.Error) } } for _, domain := range domains { // Search and compare created domains if domainRetrieved, err := domainDAO.FindByFQDN(domain.FQDN); err != nil { utils.Fatalln(fmt.Sprintf("Couldn't find created domain %s in database", domain.FQDN), err) } else if !utils.CompareDomain(*domain, domainRetrieved) { utils.Fatalln(fmt.Sprintf("Domain %s created is being persisted wrongly", domain.FQDN), nil) } } // Update domains for _, domain := range domains { domain.Owners = []model.Owner{} } domainResults = domainDAO.SaveMany(domains) for _, domainResult := range domainResults { if domainResult.Error != nil { utils.Fatalln(fmt.Sprintf("Couldn't update domain %s in database", domainResult.Domain.FQDN), domainResult.Error) } } for _, domain := range domains { // Search and compare updated domains if domainRetrieved, err := domainDAO.FindByFQDN(domain.FQDN); err != nil { utils.Fatalln(fmt.Sprintf("Couldn't find updated domain %s in database", domain.FQDN), err) } else if !utils.CompareDomain(*domain, domainRetrieved) { utils.Fatalln(fmt.Sprintf("Domain %s updated in being persisted wrongly", domain.FQDN), nil) } } // Check if find all really return all domains allDomainsChannel, err := domainDAO.FindAllAsync() if err != nil { utils.Fatalln("Error while retrieving all domains from database", err) } var allDomains []model.Domain for { domainRetrieved := <-allDomainsChannel if domainRetrieved.Error != nil { utils.Fatalln("Error while retrieving all domains from database", err) } else if domainRetrieved.Domain == nil { break } allDomains = append(allDomains, *domainRetrieved.Domain) } if len(allDomains) != len(domains) { utils.Fatalln(fmt.Sprintf("FindAll method is not returning all domains we expected %d but got %d", len(domains), len(allDomains)), nil) } // Detected a problem in FindAsync method on 2014-01-17 where we were returning the same // object many times because we were reusing the same pointer. For that reason we are // going to add a test to check if the items returned are the same set of the inserted // ones for _, domain := range domains { found := false for _, domainRetrieved := range allDomains { if domainRetrieved.Id.Hex() == domain.Id.Hex() { found = true break } } if !found { utils.Fatalln("FindAll method is not returning all objects "+ "that were inserted, apparently there are duplicated objects in the result set", nil) } } // Remove domains domainResults = domainDAO.RemoveMany(domains) for _, domainResult := range domainResults { if domainResult.Error != nil { utils.Fatalln(fmt.Sprintf("Error while trying to remove domain %s from database", domainResult.Domain.FQDN), domainResult.Error) } } for _, domain := range domains { // Check removals if _, err := domainDAO.FindByFQDN(domain.FQDN); err == nil { utils.Fatalln(fmt.Sprintf("Domain %s was not removed from database", domain.FQDN), nil) } } // Let's add and remove the domains again to test the remove all method domainResults = domainDAO.SaveMany(domains) for _, domainResult := range domainResults { if domainResult.Error != nil { utils.Fatalln(fmt.Sprintf("Couldn't save domain %s in database", domainResult.Domain.FQDN), domainResult.Error) } } if err := domainDAO.RemoveAll(); err != nil { utils.Fatalln("Couldn't remove all domains", err) } allDomainsChannel, err = domainDAO.FindAllAsync() if err != nil { utils.Fatalln("Error while retrieving all domains from database", err) } allDomains = []model.Domain{} for { domainRetrieved := <-allDomainsChannel if domainRetrieved.Error != nil { utils.Fatalln("Error while retrieving all domains from database", err) } else if domainRetrieved.Domain == nil { break } allDomains = append(allDomains, *domainRetrieved.Domain) } if len(allDomains) > 0 { utils.Fatalln("RemoveAll method is not removing the domains from the database", nil) } }
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) } }
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) } }
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) } }
// Put is responsable for checking a domain object on-the-fly without persisting in // database, useful for pre-registration validations in the registry func (h *DomainVerificationHandler) Put(w http.ResponseWriter, r *http.Request) { // We need to set the FQDN in the domain request object because it is sent only in the // URI and not in the domain request body to avoid information redudancy h.Request.FQDN = h.GetFQDN() var domain model.Domain var err error if domain, err = protocol.Merge(domain, h.Request); err != nil { messageId := "" switch err { case protocol.ErrInvalidDNSKEY: messageId = "invalid-dnskey" case protocol.ErrInvalidDSAlgorithm: messageId = "invalid-ds-algorithm" case protocol.ErrInvalidDSDigestType: messageId = "invalid-ds-digest-type" case protocol.ErrInvalidIP: messageId = "invalid-ip" case protocol.ErrInvalidLanguage: messageId = "invalid-language" } if len(messageId) == 0 { log.Println("Error while merging domain objects for domain verification "+ "operation. Details:", err) w.WriteHeader(http.StatusInternalServerError) } else { if err := h.MessageResponse(messageId, r.URL.RequestURI()); err == nil { w.WriteHeader(http.StatusBadRequest) } else { log.Println("Error while writing response. Details:", err) w.WriteHeader(http.StatusInternalServerError) } } return } scan.ScanDomain(&domain) // As we alredy did the scan, if the domain is registered in the system, we update it for this // results. This also gives a more intuitive design for when the user wants to force a check a // specific domain in the Shelter system domainDAO := dao.DomainDAO{ Database: h.GetDatabase(), } if dbDomain, err := domainDAO.FindByFQDN(domain.FQDN); err == nil { update := true // Check if we have the same nameservers, and if so update the last status if len(dbDomain.Nameservers) == len(domain.Nameservers) { for i := range dbDomain.Nameservers { dbNameserver := dbDomain.Nameservers[i] nameserver := domain.Nameservers[i] if dbNameserver.Host == nameserver.Host && dbNameserver.IPv4.Equal(nameserver.IPv4) && dbNameserver.IPv6.Equal(nameserver.IPv6) { dbDomain.Nameservers[i].ChangeStatus(nameserver.LastStatus) } else { update = false break } } } else { update = false } // Check if we have the same DS set, and if so update the last status if len(dbDomain.DSSet) == len(domain.DSSet) { for i := range dbDomain.DSSet { dbDS := dbDomain.DSSet[i] ds := domain.DSSet[i] if dbDS.Keytag == ds.Keytag && dbDS.Algorithm == ds.Algorithm && dbDS.DigestType == ds.DigestType && dbDS.Digest == ds.Digest { dbDomain.DSSet[i].ChangeStatus(ds.LastStatus) } else { update = false break } } } else { update = false } if update { // We don't care about errors resulted here, because the main idea of this service is to scan // a domaion, not persist the results domainDAO.Save(&dbDomain) } } w.WriteHeader(http.StatusOK) domainResponse := protocol.ToDomainResponse(domain, false) h.Response = &domainResponse }
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) } }