From 8302d19b42d2ff99fe71219a27f67d6aed13fa9b Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Thu, 23 Dec 2010 11:02:01 +0100 Subject: [PATCH] At least it gives formerr now --- edns.go | 50 +++++++++--------- msg.go | 122 +++++++++++++++++++++---------------------- resolverEdns_test.go | 51 ++++++++++++++++++ types.go | 53 ++++++++++--------- 4 files changed, 166 insertions(+), 110 deletions(-) create mode 100644 resolverEdns_test.go diff --git a/edns.go b/edns.go index 6191b59c..4c09678d 100644 --- a/edns.go +++ b/edns.go @@ -2,16 +2,16 @@ package dns // Implementation of EDNS0, RFC 2671 const ( - OptionCodeLLQ = 1 - OptionCodeUL = 2 - OptionCodeNSID = 3 - // EDNS flag bits (put in Z section) - _DO = 1 << 15 // dnssec ok + OptionCodeLLQ = 1 + OptionCodeUL = 2 + OptionCodeNSID = 3 + // EDNS flag bits (put in Z section) + _DO = 1 << 15 // dnssec ok ) type Option struct { - Code uint16 - Data string "hex" + Code uint16 + Data string "hex" } // EDNS extended RR. @@ -19,31 +19,31 @@ type Option struct { // the RR_Header over to this type and allow for // easy access type EDNS0_Header struct { - Name string "extended-name" - Opt uint16 // was type - UDPSize uint16 // was class - ExtendedRcode uint8 // was TTL - Version uint8 // was TTL - Z uint16 // was TTL (all flags should be put here) - Rdlength uint16 // length of data after the header + Name string "extended-name" + Opt uint16 // was type + UDPSize uint16 // was class + ExtendedRcode uint8 // was TTL + Version uint8 // was TTL + Z uint16 // was TTL (all flags should be put here) + Rdlength uint16 // length of data after the header } type RR_OPT struct { - Hdr RR_Header // this must become a EDNS0_Header - Option []Option "OPT" // Tag is used in pack and unpack + Hdr RR_Header // this must become a EDNS0_Header + Option []Option "OPT" // Tag is used in pack and unpack } func (rr *RR_OPT) Header() *RR_Header { - return &rr.Hdr + return &rr.Hdr } func (rr *RR_OPT) String() string { - s := rr.Hdr.String() - for _, o := range rr.Option { - switch o.Code { - case OptionCodeNSID: - s += "NSID: " + o.Data - } - } - return s + s := rr.Hdr.String() + for _, o := range rr.Option { + switch o.Code { + case OptionCodeNSID: + s += "NSID: " + o.Data + } + } + return s } diff --git a/msg.go b/msg.go index 3cc4a3ac..97df4694 100644 --- a/msg.go +++ b/msg.go @@ -73,13 +73,13 @@ func packDomainName(s string, msg []byte, off int, edns bool) (off1 int, ok bool s += "." } - if edns { - // packing for edns is actually easy - msg[0] = 0x40 // 01 111111 - msg[1] = 0x00 - off += 2 - return off, true - } + if edns { + // packing for edns is actually easy + msg[0] = 0x40 // 01 111111 + msg[1] = 0x00 + off += 2 + return off, true + } // Each dot ends a segment of the name. // We trade each dot byte for a length byte. @@ -146,19 +146,19 @@ Loop: } s += string(msg[off:off+c]) + "." off += c - case 0x40: - // Need a check if a RR has this, because - // we need to set RR_Heasder.Edns to true - // edns extended name, does not matter for - // the rest of the RR (which should be OPT) - // but the parsing here (is for now) relatively simple - // The name must be the root label aka 00 - // TODO check! MG - println("*** Seeing EDNS") - edns = true - s = "" - off++ - break Loop + case 0x40: + // Need a check if a RR has this, because + // we need to set RR_Heasder.Edns to true + // edns extended name, does not matter for + // the rest of the RR (which should be OPT) + // but the parsing here (is for now) relatively simple + // The name must be the root label aka 00 + // TODO check! MG + println("*** Seeing EDNS") + edns = true + s = "" + off++ + break Loop case 0xC0: // pointer to somewhere else in msg. // remember location after first ptr, @@ -199,33 +199,33 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int, edns bool) ( BadType: fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v\n", f.Type) return len(msg), false - case *reflect.BoolValue: - // Used internally for Edns, not present in the DNS - continue; + case *reflect.BoolValue: + // Used internally for Edns, not present in the DNS + continue case *reflect.SliceValue: switch f.Tag { default: fmt.Fprintf(os.Stderr, "net: dns: unknown IP tag %v\n", f.Tag) return len(msg), false - case "OPT": // edns - // Set the Hdr.Edns to true - for j := 0; j < val.Field(i).(*reflect.SliceValue).Len(); j++ { - println(j) // TODO MG - element := val.Field(i).(*reflect.SliceValue).Elem(j) - code := uint16(element.(*reflect.StructValue).Field(0).(*reflect.UintValue).Get()) - data := string(element.(*reflect.StructValue).Field(1).(*reflect.StringValue).Get()) - // Option Code - msg[off] = byte(code >> 8) - msg[off+1] = byte(code) - // Length - msg[off+2] = byte(len(data) >> 8) - msg[off+3] = byte(len(data)) - off += 4 - copy(msg[off:off+len(data)], []byte(data)) - off += len(data) // +1?? - println("data", data) - println("off", off) - } + case "OPT": // edns + // Set the Hdr.Edns to true + for j := 0; j < val.Field(i).(*reflect.SliceValue).Len(); j++ { + println(j) // TODO MG + element := val.Field(i).(*reflect.SliceValue).Elem(j) + code := uint16(element.(*reflect.StructValue).Field(0).(*reflect.UintValue).Get()) + data := string(element.(*reflect.StructValue).Field(1).(*reflect.StringValue).Get()) + // Option Code + msg[off] = byte(code >> 8) + msg[off+1] = byte(code) + // Length + msg[off+2] = byte(len(data) >> 8) + msg[off+3] = byte(len(data)) + off += 4 + copy(msg[off:off+len(data)], []byte(data)) + off += len(data) // +1?? + println("data", data) + println("off", off) + } case "A": if fv.Len() > net.IPv4len || off+fv.Len() > len(msg) { return len(msg), false @@ -293,9 +293,9 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int, edns bool) ( if !ok { return len(msg), false } - case "hex": - // TODO need this for DS - println("hex packing not implemented") + case "hex": + // TODO need this for DS + println("hex packing not implemented") case "": // Counted string: 1 byte length. if len(s) > 255 || off+1+len(s) > len(msg) { @@ -332,9 +332,9 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, BadType: fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type) return len(msg), false, false - case *reflect.BoolValue: - // Used internally for Edns, not present in the DNS - continue; + case *reflect.BoolValue: + // Used internally for Edns, not present in the DNS + continue case *reflect.SliceValue: switch f.Tag { default: @@ -356,8 +356,8 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, b := net.IP(p) fv.Set(reflect.NewValue(b).(*reflect.SliceValue)) off += net.IPv6len - case "OPT": // edns - // do it here + case "OPT": // edns + // do it here } case *reflect.StructValue: off, ok, edns = unpackStructValue(fv, msg, off) @@ -400,7 +400,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, switch val.Type().Name() { case "RR_DS": consumed = 4 // KeyTag(2) + Algorithm(1) + DigestType(1) - default: + default: consumed = 0 // TODO } s = hex.EncodeToString(msg[off : off+rdlength-consumed]) @@ -415,7 +415,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, consumed = 4 // Flags(2) + Protocol(1) + Algorithm(1) case "RR_RRSIG": consumed = 18 // TypeCovered(2) + Algorithm(1) + Labels(1) + - // OrigTTL(4) + SigExpir(4) + SigIncep(4) + KeyTag(2) + len(signername) + // OrigTTL(4) + SigExpir(4) + SigIncep(4) + KeyTag(2) + len(signername) // Should already be set in the sequence of parsing (comes before) // Work because of rfc4034, section 3.17 consumed += len(val.FieldByName("SignerName").(*reflect.StringValue).Get()) + 1 @@ -490,7 +490,7 @@ func packRR(rr RR, msg []byte, off int) (off2 int, ok bool) { // a bit inefficient but this doesn't need to be fast. // off1 is end of header // off2 is end of rr - edns := rr.Header().Edns + edns := rr.Header().Edns off1, ok = packStruct(rr.Header(), msg, off, edns) off2, ok = packStruct(rr, msg, off, edns) if !ok { @@ -506,25 +506,25 @@ func packRR(rr RR, msg []byte, off int) (off2 int, ok bool) { // Resource record unpacker. func unpackRR(msg []byte, off int) (rr RR, off1 int, ok bool) { // unpack just the header, to find the rr type and length - // check if we have an edns packet, and set h.Edns to true + // check if we have an edns packet, and set h.Edns to true var h RR_Header - var edns bool + var edns bool off0 := off if off, ok, edns = unpackStruct(&h, msg, off); !ok { return nil, len(msg), false } - h.Edns = edns // set Edns if found + h.Edns = edns // set Edns if found end := off + int(h.Rdlength) // make an rr of that type and re-unpack. // again inefficient but doesn't need to be fast. mk, known := rr_mk[int(h.Rrtype)] if !known { - return &h, end, true // false, or unknown RR?? + return &h, end, true // false, or unknown RR?? } rr = mk() - off, ok, _ = unpackStruct(rr, msg, off0) // don't care about edns? + off, ok, _ = unpackStruct(rr, msg, off0) // don't care about edns? if off != end { // added MG // println("Hier gaat het dan fout, echt waar en was if off0", off0) @@ -545,7 +545,7 @@ type MsgHdr struct { Truncated bool Recursion_desired bool Recursion_available bool - Z bool // or just zero?? + Z bool // or just zero?? Authenticated_data bool Checking_disabled bool Rcode int @@ -598,7 +598,7 @@ type Msg struct { Answer []RR Ns []RR // EDNS0 has to be put in this section - Extra []RR + Extra []RR } @@ -647,7 +647,7 @@ func (dns *Msg) Pack() (msg []byte, ok bool) { // Could work harder to calculate message size, // but this is far more than we need and not // big enough to hurt the allocator. - msg = make([]byte, 4096) // TODO, calculate REAL size + msg = make([]byte, 4096) // TODO, calculate REAL size // Pack it in: header and then the pieces. off := 0 diff --git a/resolverEdns_test.go b/resolverEdns_test.go new file mode 100644 index 00000000..885b181f --- /dev/null +++ b/resolverEdns_test.go @@ -0,0 +1,51 @@ +package dns + +import ( + "testing" + "time" + "fmt" +) + +func TestResolverEdns(t *testing.T) { + res := new(Resolver) + ch := NewQuerier(res) + + res.Servers = []string{"127.0.0.1"} + res.Timeout = 2 + res.Attempts = 1 + + m := new(Msg) + m.MsgHdr.Recursion_desired = true //only set this bit + m.Question = make([]Question, 1) + m.Extra = make([]RR, 1) + + // Add EDNS rr + edns := new(RR_OPT) + edns.Hdr.Edns = true // must be set for edns + edns.Hdr.Name = "." // must . be for edns + edns.Hdr.Rrtype = TypeOPT + edns.Hdr.Class = ClassINET + edns.Hdr.Ttl = 3600 + // no options + // edns.Option = make([]Option, 1) + // edns.Option[0].Code = OptionCodeNSID + // edns.Option[0].Data = "lalalala" + + // ask something + m.Question[0] = Question{"miek.nl", TypeSOA, ClassINET} + m.Extra[0] = edns + + fmt.Printf("%v\n", m) + + ch <- DnsMsg{m, nil} + in := <-ch + + if in.Dns.Rcode != RcodeSuccess { + t.Log("Failed to get an valid answer") + t.Fail() + } + fmt.Printf("%v\n", in) + + ch <- DnsMsg{nil, nil} + time.Sleep(1.0e9) +} diff --git a/types.go b/types.go index 7120aa51..e2288377 100644 --- a/types.go +++ b/types.go @@ -120,7 +120,7 @@ func (q *Question) String() string { // There are many types of messages, // but they all share the same header. type RR_Header struct { - Edns bool // true is this a edns header + Edns bool // true is this a edns header Name string "domain-name" Rrtype uint16 Class uint16 @@ -134,14 +134,19 @@ func (h *RR_Header) Header() *RR_Header { func (h *RR_Header) String() string { var s string - if len(h.Name) == 0 { - s = ".\t" - } else { - s = h.Name + "\t" - } - s = s + strconv.Itoa(int(h.Ttl)) + "\t" - s = s + class_str[h.Class] + "\t" - s = s + rr_str[h.Rrtype] + "\t" + + if h.Edns { + s = ";" + } + + if len(h.Name) == 0 { + s += ".\t" + } else { + s += h.Name + "\t" + } + s = s + strconv.Itoa(int(h.Ttl)) + "\t" + s = s + class_str[h.Class] + "\t" + s = s + rr_str[h.Rrtype] + "\t" return s } @@ -354,16 +359,16 @@ func (rr *RR_AAAA) String() string { // DNSSEC types type RR_RRSIG struct { - Hdr RR_Header - TypeCovered uint16 - Algorithm uint8 - Labels uint8 - OrigTtl uint32 - Expiration uint32 - Inception uint32 - KeyTag uint16 - SignerName string "domain-name" - Sig string "base64" + Hdr RR_Header + TypeCovered uint16 + Algorithm uint8 + Labels uint8 + OrigTtl uint32 + Expiration uint32 + Inception uint32 + KeyTag uint16 + SignerName string "domain-name" + Sig string "base64" } func (rr *RR_RRSIG) Header() *RR_Header { @@ -376,8 +381,8 @@ func (rr *RR_RRSIG) Header() *RR_Header { // needs serial stuff // starts when 1970 has been 68 years ago?? func intToDate(t uint32) string { -// als meer dan 68 jaar geleden, dan 68 jaar bij bedrag optellen -// TODO + // als meer dan 68 jaar geleden, dan 68 jaar bij bedrag optellen + // TODO ti := time.SecondsToUTC(int64(t)) return ti.Format("20060102030405") } @@ -389,9 +394,9 @@ func (rr *RR_RRSIG) String() string { " " + strconv.Itoa(int(rr.Algorithm)) + " " + strconv.Itoa(int(rr.Labels)) + " " + strconv.Itoa(int(rr.OrigTtl)) + -// " " + strconv.Itoa(int(rr.Expiration)) + // date calc! TODO + // " " + strconv.Itoa(int(rr.Expiration)) + // date calc! TODO " " + intToDate(rr.Expiration) + -// " " + strconv.Itoa(int(rr.Inception)) + // date calc! TODO + // " " + strconv.Itoa(int(rr.Inception)) + // date calc! TODO " " + intToDate(rr.Inception) + " " + strconv.Itoa(int(rr.KeyTag)) + " " + rr.SignerName + @@ -515,7 +520,7 @@ var rr_str = map[uint16]string{ TypeSRV: "SRV", TypeA: "A", TypeAAAA: "AAAA", - TypeOPT: "OPT", + TypeOPT: "OPT", TypeDS: "DS", TypeRRSIG: "RRSIG", TypeNSEC: "NSEC",