func ExamplePrivateHandle() { dns.PrivateHandle("APAIR", TypeAPAIR, NewAPAIR) defer dns.PrivateHandleRemove(TypeAPAIR) rr, err := dns.NewRR("miek.nl. APAIR (1.2.3.4 1.2.3.5)") if err != nil { log.Fatal("could not parse APAIR record: ", err) } fmt.Println(rr) // Output: miek.nl. 3600 IN APAIR 1.2.3.4 1.2.3.5 m := new(dns.Msg) m.Id = 12345 m.SetQuestion("miek.nl.", TypeAPAIR) m.Answer = append(m.Answer, rr) fmt.Println(m) // ;; opcode: QUERY, status: NOERROR, id: 12345 // ;; flags: rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 // // ;; QUESTION SECTION: // ;miek.nl. IN APAIR // // ;; ANSWER SECTION: // miek.nl. 3600 IN APAIR 1.2.3.4 1.2.3.5 }
// Retrieve the MX records for miek.nl. func ExampleMX() { config, _ := dns.ClientConfigFromFile("/etc/resolv.conf") c := new(dns.Client) m := new(dns.Msg) m.SetQuestion("miek.nl.", dns.TypeMX) m.RecursionDesired = true r, _, err := c.Exchange(m, config.Servers[0]+":"+config.Port) if err != nil { return } if r.Rcode != dns.RcodeSuccess { return } for _, a := range r.Answer { if mx, ok := a.(*dns.MX); ok { fmt.Printf("%s\n", mx.String()) } } }
// Verify the DNS configuration on the nameservers. This method will send a SOA request // for each nameserver and verify the results. Returns true if nameserver is done checking // and can be saved or false otherwise, that indicates that the domain was postponed func (q *querier) checkNameserver(domain *model.Domain, index int, postponedDomains []postponedDomain) bool { nameserver := domain.Nameservers[index] domainNSPolicy := nspolicy.NewDomainNSPolicy(domain) // Build message to send the request var dnsRequestMessage dns.Msg dnsRequestMessage.SetQuestion(domain.FQDN, dns.TypeSOA) dnsRequestMessage.RecursionDesired = false host, err := getHost(domain.FQDN, nameserver) if err == ErrHostTimeout { domain.Nameservers[index].ChangeStatus(model.NameserverStatusTimeout) return true } else if err == ErrHostQPSExceeded { postponedDomains = append(postponedDomains, postponedDomain{ domain: domain, index: index, }) return false } dnsResponseMessage, err := q.sendDNSRequest(host, &dnsRequestMessage) querierCache.Query(nameserver.Host) if status := domainNSPolicy.CheckNetworkError(err); status != model.NameserverStatusOK { if status == model.NameserverStatusTimeout { querierCache.Timeout(nameserver.Host) } domain.Nameservers[index].ChangeStatus(status) } else { domain.Nameservers[index].ChangeStatus(domainNSPolicy.Run(dnsResponseMessage)) } return true }
// Retrieve the DNSKEY records of a zone and convert them // to DS records for SHA1, SHA256 and SHA384. func ExampleDS(zone string) { config, _ := dns.ClientConfigFromFile("/etc/resolv.conf") c := new(dns.Client) m := new(dns.Msg) if zone == "" { zone = "miek.nl" } m.SetQuestion(dns.Fqdn(zone), dns.TypeDNSKEY) m.SetEdns0(4096, true) r, _, err := c.Exchange(m, config.Servers[0]+":"+config.Port) if err != nil { return } if r.Rcode != dns.RcodeSuccess { return } for _, k := range r.Answer { if key, ok := k.(*dns.DNSKEY); ok { for _, alg := range []uint8{dns.SHA1, dns.SHA256, dns.SHA384} { fmt.Printf("%s; %d\n", key.ToDS(alg).String(), key.Flags) } } } }
// Check the DS with the domain DNSSEC keys and signatures. You need also to inform the // UDP max package size supported to pass into firewalls. Many firewalls don't allow // fragmented UDP packages or UDP packages bigger than 512 bytes. Returns true if DS set // is done checking and can be saved or false otherwise, that indicates that the domain // was postponed func (q *querier) checkDS(domain *model.Domain, index int, udpMaxSize uint16, postponedDomains []postponedDomain) bool { // Check if the domain has DNSSEC, this system will work with both kinds of domain. So // when the domain don't have any DS record we assume that it does not have DNSSEC // configured and check only the DNS configuration if len(domain.DSSet) == 0 { return true } nameserver := domain.Nameservers[index] domainDSPolicy := dspolicy.NewDomainDSPolicy(domain) // We are going to request the DNSSEC keys to validate with the DS information that we // have from the domain var dnsRequestMessage dns.Msg dnsRequestMessage.SetQuestion(domain.FQDN, dns.TypeDNSKEY) dnsRequestMessage.RecursionDesired = false dnsRequestMessage.SetEdns0(udpMaxSize, true) host, err := getHost(domain.FQDN, nameserver) if err == ErrHostTimeout { for index, _ := range domain.DSSet { domain.DSSet[index].ChangeStatus(model.DSStatusTimeout) } return true } else if err == ErrHostQPSExceeded { postponedDomains = append(postponedDomains, postponedDomain{ domain: domain, index: index, }) return false } dnsResponseMessage, err := q.sendDNSRequest(host, &dnsRequestMessage) querierCache.Query(nameserver.Host) if domainDSPolicy.CheckNetworkError(err) { domainDSPolicy.Run(dnsResponseMessage) } return true }
// 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 }