diff options
Diffstat (limited to 'src/pkg/net/dnsmsg.go')
-rw-r--r-- | src/pkg/net/dnsmsg.go | 145 |
1 files changed, 86 insertions, 59 deletions
diff --git a/src/pkg/net/dnsmsg.go b/src/pkg/net/dnsmsg.go index dc195caf8..e8eb8d958 100644 --- a/src/pkg/net/dnsmsg.go +++ b/src/pkg/net/dnsmsg.go @@ -50,6 +50,7 @@ const ( dnsTypeMINFO = 14 dnsTypeMX = 15 dnsTypeTXT = 16 + dnsTypeAAAA = 28 dnsTypeSRV = 33 // valid dnsQuestion.qtype only @@ -244,8 +245,18 @@ type dnsRR_A struct { A uint32 "ipv4" } -func (rr *dnsRR_A) Header() *dnsRR_Header { return &rr.Hdr } +func (rr *dnsRR_A) Header() *dnsRR_Header { + return &rr.Hdr +} + +type dnsRR_AAAA struct { + Hdr dnsRR_Header + AAAA [16]byte "ipv6" +} +func (rr *dnsRR_AAAA) Header() *dnsRR_Header { + return &rr.Hdr +} // Packing and unpacking. // @@ -270,6 +281,7 @@ var rr_mk = map[int]func() dnsRR{ dnsTypeTXT: func() dnsRR { return new(dnsRR_TXT) }, dnsTypeSRV: func() dnsRR { return new(dnsRR_SRV) }, dnsTypeA: func() dnsRR { return new(dnsRR_A) }, + dnsTypeAAAA: func() dnsRR { return new(dnsRR_AAAA) }, } // Pack a domain name s into msg[off:]. @@ -377,43 +389,49 @@ Loop: // TODO(rsc): Move into generic library? // Pack a reflect.StructValue into msg. Struct members can only be uint16, uint32, string, -// and other (often anonymous) structs. -func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) { +// [n]byte, and other (often anonymous) structs. +func packStructValue(val reflect.Value, 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) { + f := val.Type().Field(i) + switch fv := val.Field(i); fv.Kind() { default: BadType: fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type) return len(msg), false - case *reflect.StructValue: + case reflect.Struct: off, ok = packStructValue(fv, msg, off) - case *reflect.UintValue: - i := fv.Get() - switch fv.Type().Kind() { - default: + case reflect.Uint16: + if off+2 > len(msg) { + return len(msg), false + } + i := fv.Uint() + msg[off] = byte(i >> 8) + msg[off+1] = byte(i) + off += 2 + case reflect.Uint32: + if off+4 > len(msg) { + return len(msg), false + } + i := fv.Uint() + msg[off] = byte(i >> 24) + msg[off+1] = byte(i >> 16) + msg[off+2] = byte(i >> 8) + msg[off+3] = byte(i) + off += 4 + case reflect.Array: + if fv.Type().Elem().Kind() != reflect.Uint8 { goto BadType - case reflect.Uint16: - if off+2 > len(msg) { - return len(msg), false - } - msg[off] = byte(i >> 8) - msg[off+1] = byte(i) - off += 2 - case reflect.Uint32: - if off+4 > len(msg) { - return len(msg), false - } - msg[off] = byte(i >> 24) - msg[off+1] = byte(i >> 16) - msg[off+2] = byte(i >> 8) - msg[off+3] = byte(i) - off += 4 } - case *reflect.StringValue: + n := fv.Len() + if off+n > len(msg) { + return len(msg), false + } + reflect.Copy(reflect.NewValue(msg[off:off+n]), fv) + off += n + case reflect.String: // There are multiple string encodings. // The tag distinguishes ordinary strings from domain names. - s := fv.Get() + s := fv.String() switch f.Tag { default: fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag) @@ -437,8 +455,8 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, o return off, true } -func structValue(any interface{}) *reflect.StructValue { - return reflect.NewValue(any).(*reflect.PtrValue).Elem().(*reflect.StructValue) +func structValue(any interface{}) reflect.Value { + return reflect.NewValue(any).Elem() } func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) { @@ -449,36 +467,41 @@ func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) { // TODO(rsc): Move into generic library? // Unpack a reflect.StructValue from msg. // Same restrictions as packStructValue. -func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) { +func unpackStructValue(val reflect.Value, 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) { + f := val.Type().Field(i) + switch fv := val.Field(i); fv.Kind() { default: BadType: fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type) return len(msg), false - case *reflect.StructValue: + case reflect.Struct: off, ok = unpackStructValue(fv, msg, off) - case *reflect.UintValue: - switch fv.Type().Kind() { - default: + case reflect.Uint16: + if off+2 > len(msg) { + return len(msg), false + } + i := uint16(msg[off])<<8 | uint16(msg[off+1]) + fv.SetUint(uint64(i)) + off += 2 + case reflect.Uint32: + if off+4 > len(msg) { + return len(msg), false + } + i := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3]) + fv.SetUint(uint64(i)) + off += 4 + case reflect.Array: + if fv.Type().Elem().Kind() != reflect.Uint8 { goto BadType - case reflect.Uint16: - if off+2 > len(msg) { - 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 - } - i := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3]) - fv.Set(uint64(i)) - off += 4 } - case *reflect.StringValue: + n := fv.Len() + if off+n > len(msg) { + return len(msg), false + } + reflect.Copy(fv, reflect.NewValue(msg[off:off+n])) + off += n + case reflect.String: var s string switch f.Tag { default: @@ -502,7 +525,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, off += n s = string(b) } - fv.Set(s) + fv.SetString(s) } } return off, true @@ -515,24 +538,28 @@ func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) { // Generic struct printer. // Doesn't care about the string tag "domain-name", -// but does look for an "ipv4" tag on uint32 variables, +// but does look for an "ipv4" tag on uint32 variables +// and the "ipv6" tag on array variables, // printing them as IP addresses. -func printStructValue(val *reflect.StructValue) string { +func printStructValue(val reflect.Value) string { s := "{" for i := 0; i < val.NumField(); i++ { if i > 0 { s += ", " } - f := val.Type().(*reflect.StructType).Field(i) + f := val.Type().Field(i) if !f.Anonymous { s += f.Name + "=" } fval := val.Field(i) - if fv, ok := fval.(*reflect.StructValue); ok { + if fv := fval; fv.Kind() == reflect.Struct { s += printStructValue(fv) - } else if fv, ok := fval.(*reflect.UintValue); ok && f.Tag == "ipv4" { - i := fv.Get() + } else if fv := fval; (fv.Kind() == reflect.Uint || fv.Kind() == reflect.Uint8 || fv.Kind() == reflect.Uint16 || fv.Kind() == reflect.Uint32 || fv.Kind() == reflect.Uint64 || fv.Kind() == reflect.Uintptr) && f.Tag == "ipv4" { + i := fv.Uint() s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String() + } else if fv := fval; fv.Kind() == reflect.Array && f.Tag == "ipv6" { + i := fv.Interface().([]byte) + s += IP(i).String() } else { s += fmt.Sprint(fval.Interface()) } |