From d87e7eff8613656c9f35da7a4d6c78fd7e56d406 Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Thu, 3 Feb 2011 20:39:43 +0100 Subject: [PATCH] support nsec3 and nsec3param --- msg.go | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++----- tsig.go | 6 ++-- types.go | 6 ++-- 3 files changed, 85 insertions(+), 13 deletions(-) diff --git a/msg.go b/msg.go index b2971a95..dd8907df 100644 --- a/msg.go +++ b/msg.go @@ -15,7 +15,6 @@ package dns import ( -// "fmt" "os" "reflect" "net" @@ -23,6 +22,7 @@ import ( "time" "strconv" "encoding/base64" + "encoding/base32" "encoding/hex" ) @@ -261,7 +261,7 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, o // for each code we should do something else h, e := hex.DecodeString(string(element.(*reflect.StructValue).Field(1).(*reflect.StringValue).Get())) if e != nil { - //fmt.Fprintf(os.Stderr, "dns: failure packing OTP") + //fmt.Fprintf(os.Stderr, "dns: failure packing OTP") return len(msg), false } data := string(h) @@ -363,8 +363,23 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, o default: //fmt.Fprintf(os.Stderr, "dns: unknown packing string tag %v", f.Tag) return len(msg), false + case "base32": + b32, err := packBase32([]byte(s)) + if err != nil { + //fmt.Fprintf(os.Stderr, "dns: overflow packing base32") + return len(msg), false + } + copy(msg[off:off+len(b32)], b32) + off += len(b32) case "base64": - // TODO(mg) use the Len as return from the conversion (not used right now) + b64, err := packBase64([]byte(s)) + if err != nil { + //fmt.Fprintf(os.Stderr, "dns: overflow packing base64") + return len(msg), false + } + copy(msg[off:off+len(b64)], b64) + off += len(b64) + /* b64len := base64.StdEncoding.DecodedLen(len(s)) _, err := base64.StdEncoding.Decode(msg[off:off+b64len], []byte(s)) if err != nil { @@ -372,12 +387,14 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, o return len(msg), false } off += b64len + */ case "domain-name": off, ok = packDomainName(s, msg, off) if !ok { //fmt.Fprintf(os.Stderr, "dns: overflow packing domain-name") return len(msg), false } + case "size-hex": case "hex": // There is no length encoded here, for DS at least h, e := hex.DecodeString(s) @@ -387,7 +404,7 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, o } copy(msg[off:off+hex.DecodedLen(len(s))], h) off += hex.DecodedLen(len(s)) - case "fixed-size": + case "size": // the size is already encoded in the RR, we can safely use the // length of string. String is RAW (not encoded in hex, nor base64) copy(msg[off:off+len(s)], s) @@ -612,7 +629,43 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, //fmt.Fprintf(os.Stderr, "dns: failure unpacking domain-name") return len(msg), false } - case "fixed-size": + case "size-base32": + var size int + switch val.Type().Name() { + case "RR_NSEC3": + switch f.Name { + case "NextDomain": + name := val.FieldByName("HashLength") + size = int(name.(*reflect.UintValue).Get()) + } + } + if off+size > len(msg) { + //fmt.Fprintf(os.Stderr, "dns: failure unpacking size-base32 string") + return len(msg), false + } + s = unpackBase32(msg[off : off+size]) + off += size + case "size-hex": + // a "size" string, but a it must be encoded in hex in the string + var size int + switch val.Type().Name() { + case "RR_NSEC3": + switch f.Name { + case "Salt": + name := val.FieldByName("SaltLength") + size = int(name.(*reflect.UintValue).Get()) + case "NextDomain": + name := val.FieldByName("HashLength") + size = int(name.(*reflect.UintValue).Get()) + } + } + if off+size > len(msg) { + //fmt.Fprintf(os.Stderr, "dns: failure unpacking hex-size string") + return len(msg), false + } + s = hex.EncodeToString(msg[off : off+size]) + off += size + case "size": // We should already know how many bytes we can expect // TODO(mg) pack variant. Note that looks a bit like the EDNS0 // Option parsing, maybe it should be merged. @@ -629,7 +682,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, } } if off+size > len(msg) { - //fmt.Fprintf(os.Stderr, "dns: failure unpacking fixed-size string") + //fmt.Fprintf(os.Stderr, "dns: failure unpacking size string") return len(msg), false } s = string(msg[off : off+size]) @@ -666,6 +719,12 @@ func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) { return off, ok } +func unpackBase32(b []byte) string { + b32 := make([]byte, base32.HexEncoding.EncodedLen(len(b))) + base32.HexEncoding.Encode(b32, b) + return string(b32) +} + func unpackBase64(b []byte) string { b64 := make([]byte, base64.StdEncoding.EncodedLen(len(b))) base64.StdEncoding.Encode(b64, b) @@ -684,6 +743,18 @@ func packBase64(s []byte) ([]byte, os.Error) { return buf, nil } +// Helper function for packing, mostly used in dnssec.go +func packBase32(s []byte) ([]byte, os.Error) { + b32len := base32.HexEncoding.DecodedLen(len(s)) + buf := make([]byte, b32len) + n, err := base32.HexEncoding.Decode(buf, []byte(s)) + if err != nil { + return nil, err + } + buf = buf[:n] + return buf, nil +} + // Resource record packer. func packRR(rr RR, msg []byte, off int) (off2 int, ok bool) { if rr == nil { @@ -699,6 +770,7 @@ func packRR(rr RR, msg []byte, off int) (off2 int, ok bool) { off1, ok = packStruct(rr.Header(), msg, off) off2, ok = packStruct(rr, msg, off) if !ok { + println("WAAA") return len(msg), false } @@ -894,7 +966,7 @@ func (dns *Msg) Unpack(msg []byte) bool { return false } if off != len(msg) { - // TODO(mg) remove eventually + // TODO(mg) remove eventually println("extra bytes in dns packet", off, "<", len(msg)) } return true diff --git a/tsig.go b/tsig.go index ce0c9513..b2d3ee1c 100644 --- a/tsig.go +++ b/tsig.go @@ -23,11 +23,11 @@ type RR_TSIG struct { TimeSigned uint64 Fudge uint16 MACSize uint16 - MAC string "fixed-size" + MAC string "size-hex" OrigId uint16 Error uint16 OtherLen uint16 - OtherData string "fixed-size" + OtherData string "size-hex" } func (rr *RR_TSIG) Header() *RR_Header { @@ -60,7 +60,7 @@ type tsigWireFmt struct { // MACSize, MAC and OrigId excluded Error uint16 OtherLen uint16 - OtherData string "fixed-size" + OtherData string "size-hex" } // Generate the HMAC for message. The TSIG RR is modified diff --git a/types.go b/types.go index 7aa2adf2..b544ee1e 100644 --- a/types.go +++ b/types.go @@ -534,9 +534,9 @@ type RR_NSEC3 struct { Flags uint8 Iterations uint16 SaltLength uint8 - Salt string "hex" + Salt string "size-hex" HashLength uint8 - NextDomain string "domain-name" + NextDomain string "size-base32" TypeBitMap []uint16 "NSEC" } @@ -553,7 +553,7 @@ func (rr *RR_NSEC3) String() string { " " + rr.NextDomain // must base32? for i := 0; i < len(rr.TypeBitMap); i++ { // Check if map exists, otherwise "TYPE" + strcov.Itoa(int(rr.TypeBitMap[i])) - s = s + " " + Rr_str[rr.TypeBitMap[i]] + s += " " + Rr_str[rr.TypeBitMap[i]] } return s }