package dnsimport ()const hexDigit = "0123456789abcdef"// Everything is assumed in ClassINET.// SetReply creates a reply message from a request message.func ( *Msg) ( *Msg) *Msg { .Id = .Id .Response = true .Opcode = .Opcodeif .Opcode == OpcodeQuery { .RecursionDesired = .RecursionDesired// Copy rd bit .CheckingDisabled = .CheckingDisabled// Copy cd bit } .Rcode = RcodeSuccessiflen(.Question) > 0 { .Question = []Question{.Question[0]} }return}// SetQuestion creates a question message, it sets the Question// section, generates an Id and sets the RecursionDesired (RD)// bit to true.func ( *Msg) ( string, uint16) *Msg { .Id = Id() .RecursionDesired = true .Question = make([]Question, 1) .Question[0] = Question{, , ClassINET}return}// SetNotify creates a notify message, it sets the Question// section, generates an Id and sets the Authoritative (AA)// bit to true.func ( *Msg) ( string) *Msg { .Opcode = OpcodeNotify .Authoritative = true .Id = Id() .Question = make([]Question, 1) .Question[0] = Question{, TypeSOA, ClassINET}return}// SetRcode creates an error message suitable for the request.func ( *Msg) ( *Msg, int) *Msg { .SetReply() .Rcode = return}// SetRcodeFormatError creates a message with FormError set.func ( *Msg) ( *Msg) *Msg { .Rcode = RcodeFormatError .Opcode = OpcodeQuery .Response = true .Authoritative = false .Id = .Idreturn}// SetUpdate makes the message a dynamic update message. It// sets the ZONE section to: z, TypeSOA, ClassINET.func ( *Msg) ( string) *Msg { .Id = Id() .Response = false .Opcode = OpcodeUpdate .Compress = false// BIND9 cannot handle compression .Question = make([]Question, 1) .Question[0] = Question{, TypeSOA, ClassINET}return}// SetIxfr creates message for requesting an IXFR.func ( *Msg) ( string, uint32, , string) *Msg { .Id = Id() .Question = make([]Question, 1) .Ns = make([]RR, 1) := new(SOA) .Hdr = RR_Header{, TypeSOA, ClassINET, defaultTtl, 0} .Serial = .Ns = .Mbox = .Question[0] = Question{, TypeIXFR, ClassINET} .Ns[0] = return}// SetAxfr creates message for requesting an AXFR.func ( *Msg) ( string) *Msg { .Id = Id() .Question = make([]Question, 1) .Question[0] = Question{, TypeAXFR, ClassINET}return}// SetTsig appends a TSIG RR to the message.// This is only a skeleton TSIG RR that is added as the last RR in the// additional section. The TSIG is calculated when the message is being send.func ( *Msg) (, string, uint16, int64) *Msg { := new(TSIG) .Hdr = RR_Header{, TypeTSIG, ClassANY, 0, 0} .Algorithm = .Fudge = .TimeSigned = uint64() .OrigId = .Id .Extra = append(.Extra, )return}// SetEdns0 appends a EDNS0 OPT RR to the message.// TSIG should always the last RR in a message.func ( *Msg) ( uint16, bool) *Msg { := new(OPT) .Hdr.Name = "." .Hdr.Rrtype = TypeOPT .SetUDPSize()if { .SetDo() } .Extra = append(.Extra, )return}// IsTsig checks if the message has a TSIG record as the last record// in the additional section. It returns the TSIG record found or nil.func ( *Msg) () *TSIG {iflen(.Extra) > 0 {if .Extra[len(.Extra)-1].Header().Rrtype == TypeTSIG {return .Extra[len(.Extra)-1].(*TSIG) } }returnnil}// IsEdns0 checks if the message has a EDNS0 (OPT) record, any EDNS0// record in the additional section will do. It returns the OPT record// found or nil.func ( *Msg) () *OPT {// RFC 6891, Section 6.1.1 allows the OPT record to appear // anywhere in the additional record section, but it's usually at // the end so start there.for := len(.Extra) - 1; >= 0; -- {if .Extra[].Header().Rrtype == TypeOPT {return .Extra[].(*OPT) } }returnnil}// popEdns0 is like IsEdns0, but it removes the record from the message.func ( *Msg) () *OPT {// RFC 6891, Section 6.1.1 allows the OPT record to appear // anywhere in the additional record section, but it's usually at // the end so start there.for := len(.Extra) - 1; >= 0; -- {if .Extra[].Header().Rrtype == TypeOPT { := .Extra[].(*OPT) .Extra = append(.Extra[:], .Extra[+1:]...)return } }returnnil}// IsDomainName checks if s is a valid domain name, it returns the number of// labels and true, when a domain name is valid. Note that non fully qualified// domain name is considered valid, in this case the last label is counted in// the number of labels. When false is returned the number of labels is not// defined. Also note that this function is extremely liberal; almost any// string is a valid domain name as the DNS is 8 bit protocol. It checks if each// label fits in 63 characters and that the entire name will fit into the 255// octet wire format limit.func ( string) ( int, bool) {// XXX: The logic in this function was copied from packDomainName and // should be kept in sync with that function.const = 256iflen() == 0 { // Ok, for instance when dealing with update RR without any rdata.return0, false } = Fqdn()// Each dot ends a segment of the name. Except for escaped dots (\.), which // are normal dots.var (intintboolbool )for := 0; < len(); ++ {switch [] {case'\\': = !if +1 > {return , false }// check for \DDDifisDDD([+1:]) { += 3 += 3 } else { ++ ++ } = falsecase'.': = falseif == 0 && len() > 1 {// leading dots are not legal except for the root zonereturn , false }if {// two dots back to back is not legalreturn , false } = true := - if >= 1<<6 { // top two bits of length must be clearreturn , false }// off can already (we're in a loop) be bigger than lenmsg // this happens when a name isn't fully qualified += 1 + if > {return , false } ++ = + 1default: = false = false } }if {return , false }return , true}// IsSubDomain checks if child is indeed a child of the parent. If child and parent// are the same domain true is returned as well.func (, string) bool {// Entire child is contained in parentreturnCompareDomainName(, ) == CountLabel()}// IsMsg sanity checks buf and returns an error if it isn't a valid DNS packet.// The checking is performed on the binary payload.func ( []byte) error {// Headeriflen() < headerSize {returnerrors.New("dns: bad message header") }// Header: Opcode // TODO(miek): more checks here, e.g. check all header bits.returnnil}// IsFqdn checks if a domain name is fully qualified.func ( string) bool {// Check for (and remove) a trailing dot, returning if there isn't one.if == "" || [len()-1] != '.' {returnfalse } = [:len()-1]// If we don't have an escape sequence before the final dot, we know it's // fully qualified and can return here.if == "" || [len()-1] != '\\' {returntrue }// Otherwise we have to check if the dot is escaped or not by checking if // there are an odd or even number of escape sequences before the dot. := strings.LastIndexFunc(, func( rune) bool {return != '\\' })return (len()-)%2 != 0}// IsRRset reports whether a set of RRs is a valid RRset as defined by RFC 2181.// This means the RRs need to have the same type, name, and class.func ( []RR) bool {iflen() == 0 {returnfalse } := [0].Header()for , := range [1:] { := .Header()if .Rrtype != .Rrtype || .Class != .Class || .Name != .Name {// Mismatch between the records, so this is not a valid rrset for // signing/verifyingreturnfalse } }returntrue}// Fqdn return the fully qualified domain name from s.// If s is already fully qualified, it behaves as the identity function.func ( string) string {ifIsFqdn() {return }return + "."}// CanonicalName returns the domain name in canonical form. A name in canonical// form is lowercase and fully qualified. Only US-ASCII letters are affected. See// Section 6.2 in RFC 4034.func ( string) string {returnstrings.Map(func( rune) rune {if >= 'A' && <= 'Z' { += 'a' - 'A' }return }, Fqdn())}// Copied from the official Go code.// ReverseAddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP// address suitable for reverse DNS (PTR) record lookups or an error if it fails// to parse the IP address.func ( string) ( string, error) { := net.ParseIP()if == nil {return"", &Error{err: "unrecognized address: " + } }if := .To4(); != nil { := make([]byte, 0, net.IPv4len*4+len("in-addr.arpa."))// Add it, in reverse, to the bufferfor := len() - 1; >= 0; -- { = strconv.AppendInt(, int64([]), 10) = append(, '.') }// Append "in-addr.arpa." and return (buf already has the final .) = append(, "in-addr.arpa."...)returnstring(), nil }// Must be IPv6 := make([]byte, 0, net.IPv6len*4+len("ip6.arpa."))// Add it, in reverse, to the bufferfor := len() - 1; >= 0; -- { := [] = append(, hexDigit[&0xF], '.', hexDigit[>>4], '.') }// Append "ip6.arpa." and return (buf already has the final .) = append(, "ip6.arpa."...)returnstring(), nil}// String returns the string representation for the type t.func ( Type) () string {if , := TypeToString[uint16()]; {return }return"TYPE" + strconv.Itoa(int())}// String returns the string representation for the class c.func ( Class) () string {if , := ClassToString[uint16()]; {// Only emit mnemonics when they are unambiguous, specially ANY is in both.if , := StringToType[]; ! {return } }return"CLASS" + strconv.Itoa(int())}// String returns the string representation for the name n.func ( Name) () string {returnsprintName(string())}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.