From 18afd5e536d1542bb181bdf0c82bdffb86def05b Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Thu, 23 Dec 2010 14:07:35 +0100 Subject: [PATCH] EDNS is easy Only the OPT RR needs to be supported --- Makefile | 5 +- edns.go | 6 +-- ednstest.go | 36 +++++++++++++++ msg.go | 108 +++++++++++++++++-------------------------- resolverEdns_test.go | 6 +-- 5 files changed, 88 insertions(+), 73 deletions(-) create mode 100644 ednstest.go diff --git a/Makefile b/Makefile index 9fac694d..5a0a7020 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ GOFILES=\ include $(GOROOT)/src/Make.pkg -p: restest manglertest ednstest dnssectest +p: restest manglertest ednstest dnssectest ednstest2 # too lazy to lookup how this works again in Makefiles restest: restest.go $(GOFILES) @@ -23,6 +23,9 @@ restest: restest.go $(GOFILES) ednstest: ednstest.go $(GOFILES) 6g -I _obj ednstest.go && 6l -L _obj -o ednstest ednstest.6 +ednstest2: ednstest2.go $(GOFILES) + 6g -I _obj ednstest2.go && 6l -L _obj -o ednstest2 ednstest2.6 + manglertest: manglertest.go $(GOFILES) 6g -I _obj manglertest.go && 6l -L _obj -o manglertest manglertest.6 diff --git a/edns.go b/edns.go index 4c09678d..72fcde45 100644 --- a/edns.go +++ b/edns.go @@ -15,12 +15,10 @@ type Option struct { } // EDNS extended RR. -// If we are dealing with this, we might copy -// the RR_Header over to this type and allow for -// easy access +// Not used yet type EDNS0_Header struct { Name string "extended-name" - Opt uint16 // was type + Opt uint16 // was type, but is always TypeOPT UDPSize uint16 // was class ExtendedRcode uint8 // was TTL Version uint8 // was TTL diff --git a/ednstest.go b/ednstest.go new file mode 100644 index 00000000..4038d94a --- /dev/null +++ b/ednstest.go @@ -0,0 +1,36 @@ +package main + +// Test EDNS RR records +import ( + "fmt" + "dns" +) + +func main() { + sig := new(dns.RR_RRSIG) + sig.Hdr.Name = "miek.nl." + sig.Hdr.Rrtype = dns.TypeRRSIG + sig.Hdr.Class = dns.ClassINET + sig.Hdr.Ttl = 3600 + sig.TypeCovered = dns.TypeDNSKEY + sig.Algorithm = dns.AlgRSASHA1 + sig.Labels = 2 + sig.OrigTtl = 4000 + sig.Expiration = 1000 + sig.Inception = 800 + sig.KeyTag = 34641 + sig.SignerName = "miek.nl." + sig.Sig = "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ" + + fmt.Printf("%v\n", sig) + + edns := new(dns.RR_OPT) + edns.Hdr.Name = "miek.nl." + edns.Hdr.Rrtype = dns.TypeOPT + edns.Hdr.Class = dns.ClassINET + edns.Hdr.Ttl = 3600 + edns.Option = make([]dns.Option, 1) + edns.Option[0].Code = dns.OptionCodeNSID + edns.Option[0].Data = "lalalala" + fmt.Printf("%v\n", edns) +} diff --git a/msg.go b/msg.go index 97df4694..53885d7c 100644 --- a/msg.go +++ b/msg.go @@ -67,20 +67,12 @@ var rcode_str = map[int]string{ // Pack a domain name s into msg[off:]. // Domain names are a sequence of counted strings // split at the dots. They end with a zero-length string. -func packDomainName(s string, msg []byte, off int, edns bool) (off1 int, ok bool) { +func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) { // Add trailing dot to canonicalize name. if n := len(s); n == 0 || s[n-1] != '.' { s += "." } - 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. // There is also a trailing zero. @@ -106,6 +98,10 @@ func packDomainName(s string, msg []byte, off int, edns bool) (off1 int, ok bool begin = i + 1 } } + // Root label is special + if s == "." { + return off,true + } msg[off] = 0 off++ return off, true @@ -124,13 +120,13 @@ func packDomainName(s string, msg []byte, off int, edns bool) (off1 int, ok bool // which is where the next record will start. // In theory, the pointers are only allowed to jump backward. // We let them jump anywhere and stop jumping after a while. -func unpackDomainName(msg []byte, off int) (s string, off1 int, ok, edns bool) { +func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) { s = "" ptr := 0 // number of pointers followed Loop: for { if off >= len(msg) { - return "", len(msg), false, false + return "", len(msg), false } c := int(msg[off]) off++ @@ -142,23 +138,10 @@ Loop: } // literal string if off+c > len(msg) { - return "", len(msg), false, false + return "", len(msg), false } 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 0xC0: // pointer to somewhere else in msg. // remember location after first ptr, @@ -166,7 +149,7 @@ Loop: // also, don't follow too many pointers -- // maybe there's a loop. if off >= len(msg) { - return "", len(msg), false, false + return "", len(msg), false } c1 := msg[off] off++ @@ -174,24 +157,24 @@ Loop: off1 = off } if ptr++; ptr > 10 { - return "", len(msg), false, false + return "", len(msg), false } off = (c^0xC0)<<8 | int(c1) default: // 0x80 and 0x40 are reserved - return "", len(msg), false, false + return "", len(msg), false } } if ptr == 0 { off1 = off } - return s, off1, true, edns + return s, off1, true } // TODO(rsc): Move into generic library? // Pack a reflect.StructValue into msg. Struct members can only be uint8, uint16, uint32, string, // slices and other (often anonymous) structs. -func packStructValue(val *reflect.StructValue, msg []byte, off int, edns bool) (off1 int, ok bool) { +func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) { for i := 0; i < val.NumField(); i++ { f := val.Type().(*reflect.StructType).Field(i) switch fv := val.Field(i).(type) { @@ -208,7 +191,6 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int, edns bool) ( 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) @@ -245,7 +227,7 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int, edns bool) ( } } case *reflect.StructValue: - off, ok = packStructValue(fv, msg, off, edns) + off, ok = packStructValue(fv, msg, off) case *reflect.UintValue: i := fv.Get() switch fv.Type().Kind() { @@ -289,7 +271,7 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int, edns bool) ( } off += b64len case "domain-name": - off, ok = packDomainName(s, msg, off, edns) + off, ok = packDomainName(s, msg, off) if !ok { return len(msg), false } @@ -317,21 +299,21 @@ func structValue(any interface{}) *reflect.StructValue { return reflect.NewValue(any).(*reflect.PtrValue).Elem().(*reflect.StructValue) } -func packStruct(any interface{}, msg []byte, off int, edns bool) (off1 int, ok bool) { - off, ok = packStructValue(structValue(any), msg, off, edns) +func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) { + off, ok = packStructValue(structValue(any), msg, off) return off, ok } // Unpack a reflect.StructValue from msg. // Same restrictions as packStructValue. -func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok, edns bool) { +func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) { for i := 0; i < val.NumField(); i++ { f := val.Type().(*reflect.StructType).Field(i) switch fv := val.Field(i).(type) { default: BadType: fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type) - return len(msg), false, false + return len(msg), false case *reflect.BoolValue: // Used internally for Edns, not present in the DNS continue @@ -339,17 +321,17 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, switch f.Tag { default: fmt.Fprintf(os.Stderr, "net: dns: unknown IP tag %v", f.Tag) - return len(msg), false, false + return len(msg), false case "A": if off+net.IPv4len > len(msg) { - return len(msg), false, false + return len(msg), false } b := net.IPv4(msg[off], msg[off+1], msg[off+2], msg[off+3]) fv.Set(reflect.NewValue(b).(*reflect.SliceValue)) off += net.IPv4len case "AAAA": if off+net.IPv6len > len(msg) { - return len(msg), false, false + return len(msg), false } p := make(net.IP, net.IPv6len) copy(p, msg[off:off+net.IPv6len]) @@ -360,28 +342,28 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, // do it here } case *reflect.StructValue: - off, ok, edns = unpackStructValue(fv, msg, off) + off, ok = unpackStructValue(fv, msg, off) case *reflect.UintValue: switch fv.Type().Kind() { default: goto BadType case reflect.Uint8: if off+1 > len(msg) { - return len(msg), false, false + return len(msg), false } i := uint8(msg[off]) fv.Set(uint64(i)) off++ case reflect.Uint16: if off+2 > len(msg) { - return len(msg), false, false + return len(msg), false } i := uint16(msg[off])<<8 | uint16(msg[off+1]) fv.Set(uint64(i)) off += 2 case reflect.Uint32: if off+4 > len(msg) { - return len(msg), false, false + return len(msg), false } i := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3]) fv.Set(uint64(i)) @@ -392,7 +374,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, switch f.Tag { default: fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag) - return len(msg), false, false + return len(msg), false case "hex": // Rest of the RR is hex encoded rdlength := int(val.FieldByName("Hdr").(*reflect.StructValue).FieldByName("Rdlength").(*reflect.UintValue).Get()) @@ -428,13 +410,13 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, s = string(b64) off += rdlength - consumed case "domain-name": - s, off, ok, edns = unpackDomainName(msg, off) + s, off, ok = unpackDomainName(msg, off) if !ok { - return len(msg), false, false + return len(msg), false } case "": if off >= len(msg) || off+1+int(msg[off]) > len(msg) { - return len(msg), false, false + return len(msg), false } n := int(msg[off]) off++ @@ -448,12 +430,12 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, fv.Set(s) } } - return off, true, edns + return off, true } -func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok, edns bool) { - off, ok, edns = unpackStructValue(structValue(any), msg, off) - return off, ok, edns +func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) { + off, ok = unpackStructValue(structValue(any), msg, off) + return off, ok } // THIS can GO TODO @@ -490,30 +472,26 @@ 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 - off1, ok = packStruct(rr.Header(), msg, off, edns) - off2, ok = packStruct(rr, msg, off, edns) + off1, ok = packStruct(rr.Header(), msg, off) + off2, ok = packStruct(rr, msg, off) if !ok { return len(msg), false } // TODO make this quicker? // pack a third time; redo header with correct data length rr.Header().Rdlength = uint16(off2 - off1) - packStruct(rr.Header(), msg, off, edns) + packStruct(rr.Header(), msg, off) return off2, true } // 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 var h RR_Header - var edns bool off0 := off - if off, ok, edns = unpackStruct(&h, msg, off); !ok { + if off, ok = unpackStruct(&h, msg, off); !ok { return nil, len(msg), false } - h.Edns = edns // set Edns if found end := off + int(h.Rdlength) // make an rr of that type and re-unpack. @@ -524,7 +502,7 @@ func unpackRR(msg []byte, off int) (rr RR, off1 int, ok bool) { } rr = mk() - off, ok, _ = unpackStruct(rr, msg, off0) // don't care about edns? + off, ok = unpackStruct(rr, msg, off0) if off != end { // added MG // println("Hier gaat het dan fout, echt waar en was if off0", off0) @@ -651,9 +629,9 @@ func (dns *Msg) Pack() (msg []byte, ok bool) { // Pack it in: header and then the pieces. off := 0 - off, ok = packStruct(&dh, msg, off, false) + off, ok = packStruct(&dh, msg, off) for i := 0; i < len(question); i++ { - off, ok = packStruct(&question[i], msg, off, false) + off, ok = packStruct(&question[i], msg, off) } for i := 0; i < len(answer); i++ { off, ok = packRR(answer[i], msg, off) @@ -675,7 +653,7 @@ func (dns *Msg) Unpack(msg []byte) bool { var dh Header off := 0 var ok bool - if off, ok, _ = unpackStruct(&dh, msg, off); !ok { + if off, ok = unpackStruct(&dh, msg, off); !ok { return false } dns.Id = dh.Id @@ -694,7 +672,7 @@ func (dns *Msg) Unpack(msg []byte) bool { dns.Extra = make([]RR, dh.Arcount) for i := 0; i < len(dns.Question); i++ { - off, ok, _ = unpackStruct(&dns.Question[i], msg, off) + off, ok = unpackStruct(&dns.Question[i], msg, off) } for i := 0; i < len(dns.Answer); i++ { dns.Answer[i], off, ok = unpackRR(msg, off) diff --git a/resolverEdns_test.go b/resolverEdns_test.go index 885b181f..dda0b009 100644 --- a/resolverEdns_test.go +++ b/resolverEdns_test.go @@ -26,7 +26,7 @@ func TestResolverEdns(t *testing.T) { edns.Hdr.Rrtype = TypeOPT edns.Hdr.Class = ClassINET edns.Hdr.Ttl = 3600 - // no options + // no options for now // edns.Option = make([]Option, 1) // edns.Option[0].Code = OptionCodeNSID // edns.Option[0].Data = "lalalala" @@ -35,7 +35,7 @@ func TestResolverEdns(t *testing.T) { m.Question[0] = Question{"miek.nl", TypeSOA, ClassINET} m.Extra[0] = edns - fmt.Printf("%v\n", m) + fmt.Printf("Sending: %v\n", m) ch <- DnsMsg{m, nil} in := <-ch @@ -44,7 +44,7 @@ func TestResolverEdns(t *testing.T) { t.Log("Failed to get an valid answer") t.Fail() } - fmt.Printf("%v\n", in) + fmt.Printf("Recv: %v\n", in.Dns) ch <- DnsMsg{nil, nil} time.Sleep(1.0e9)