At least it gives formerr now

This commit is contained in:
Miek Gieben 2010-12-23 11:02:01 +01:00
parent 4668b309e2
commit 8302d19b42
4 changed files with 166 additions and 110 deletions

50
edns.go
View File

@ -2,16 +2,16 @@ package dns
// Implementation of EDNS0, RFC 2671 // Implementation of EDNS0, RFC 2671
const ( const (
OptionCodeLLQ = 1 OptionCodeLLQ = 1
OptionCodeUL = 2 OptionCodeUL = 2
OptionCodeNSID = 3 OptionCodeNSID = 3
// EDNS flag bits (put in Z section) // EDNS flag bits (put in Z section)
_DO = 1 << 15 // dnssec ok _DO = 1 << 15 // dnssec ok
) )
type Option struct { type Option struct {
Code uint16 Code uint16
Data string "hex" Data string "hex"
} }
// EDNS extended RR. // EDNS extended RR.
@ -19,31 +19,31 @@ type Option struct {
// the RR_Header over to this type and allow for // the RR_Header over to this type and allow for
// easy access // easy access
type EDNS0_Header struct { type EDNS0_Header struct {
Name string "extended-name" Name string "extended-name"
Opt uint16 // was type Opt uint16 // was type
UDPSize uint16 // was class UDPSize uint16 // was class
ExtendedRcode uint8 // was TTL ExtendedRcode uint8 // was TTL
Version uint8 // was TTL Version uint8 // was TTL
Z uint16 // was TTL (all flags should be put here) Z uint16 // was TTL (all flags should be put here)
Rdlength uint16 // length of data after the header Rdlength uint16 // length of data after the header
} }
type RR_OPT struct { type RR_OPT struct {
Hdr RR_Header // this must become a EDNS0_Header Hdr RR_Header // this must become a EDNS0_Header
Option []Option "OPT" // Tag is used in pack and unpack Option []Option "OPT" // Tag is used in pack and unpack
} }
func (rr *RR_OPT) Header() *RR_Header { func (rr *RR_OPT) Header() *RR_Header {
return &rr.Hdr return &rr.Hdr
} }
func (rr *RR_OPT) String() string { func (rr *RR_OPT) String() string {
s := rr.Hdr.String() s := rr.Hdr.String()
for _, o := range rr.Option { for _, o := range rr.Option {
switch o.Code { switch o.Code {
case OptionCodeNSID: case OptionCodeNSID:
s += "NSID: " + o.Data s += "NSID: " + o.Data
} }
} }
return s return s
} }

122
msg.go
View File

@ -73,13 +73,13 @@ func packDomainName(s string, msg []byte, off int, edns bool) (off1 int, ok bool
s += "." s += "."
} }
if edns { if edns {
// packing for edns is actually easy // packing for edns is actually easy
msg[0] = 0x40 // 01 111111 msg[0] = 0x40 // 01 111111
msg[1] = 0x00 msg[1] = 0x00
off += 2 off += 2
return off, true return off, true
} }
// Each dot ends a segment of the name. // Each dot ends a segment of the name.
// We trade each dot byte for a length byte. // We trade each dot byte for a length byte.
@ -146,19 +146,19 @@ Loop:
} }
s += string(msg[off:off+c]) + "." s += string(msg[off:off+c]) + "."
off += c off += c
case 0x40: case 0x40:
// Need a check if a RR has this, because // Need a check if a RR has this, because
// we need to set RR_Heasder.Edns to true // we need to set RR_Heasder.Edns to true
// edns extended name, does not matter for // edns extended name, does not matter for
// the rest of the RR (which should be OPT) // the rest of the RR (which should be OPT)
// but the parsing here (is for now) relatively simple // but the parsing here (is for now) relatively simple
// The name must be the root label aka 00 // The name must be the root label aka 00
// TODO check! MG // TODO check! MG
println("*** Seeing EDNS") println("*** Seeing EDNS")
edns = true edns = true
s = "" s = ""
off++ off++
break Loop break Loop
case 0xC0: case 0xC0:
// pointer to somewhere else in msg. // pointer to somewhere else in msg.
// remember location after first ptr, // remember location after first ptr,
@ -199,33 +199,33 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int, edns bool) (
BadType: BadType:
fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v\n", f.Type) fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v\n", f.Type)
return len(msg), false return len(msg), false
case *reflect.BoolValue: case *reflect.BoolValue:
// Used internally for Edns, not present in the DNS // Used internally for Edns, not present in the DNS
continue; continue
case *reflect.SliceValue: case *reflect.SliceValue:
switch f.Tag { switch f.Tag {
default: default:
fmt.Fprintf(os.Stderr, "net: dns: unknown IP tag %v\n", f.Tag) fmt.Fprintf(os.Stderr, "net: dns: unknown IP tag %v\n", f.Tag)
return len(msg), false return len(msg), false
case "OPT": // edns case "OPT": // edns
// Set the Hdr.Edns to true // Set the Hdr.Edns to true
for j := 0; j < val.Field(i).(*reflect.SliceValue).Len(); j++ { for j := 0; j < val.Field(i).(*reflect.SliceValue).Len(); j++ {
println(j) // TODO MG println(j) // TODO MG
element := val.Field(i).(*reflect.SliceValue).Elem(j) element := val.Field(i).(*reflect.SliceValue).Elem(j)
code := uint16(element.(*reflect.StructValue).Field(0).(*reflect.UintValue).Get()) code := uint16(element.(*reflect.StructValue).Field(0).(*reflect.UintValue).Get())
data := string(element.(*reflect.StructValue).Field(1).(*reflect.StringValue).Get()) data := string(element.(*reflect.StructValue).Field(1).(*reflect.StringValue).Get())
// Option Code // Option Code
msg[off] = byte(code >> 8) msg[off] = byte(code >> 8)
msg[off+1] = byte(code) msg[off+1] = byte(code)
// Length // Length
msg[off+2] = byte(len(data) >> 8) msg[off+2] = byte(len(data) >> 8)
msg[off+3] = byte(len(data)) msg[off+3] = byte(len(data))
off += 4 off += 4
copy(msg[off:off+len(data)], []byte(data)) copy(msg[off:off+len(data)], []byte(data))
off += len(data) // +1?? off += len(data) // +1??
println("data", data) println("data", data)
println("off", off) println("off", off)
} }
case "A": case "A":
if fv.Len() > net.IPv4len || off+fv.Len() > len(msg) { if fv.Len() > net.IPv4len || off+fv.Len() > len(msg) {
return len(msg), false return len(msg), false
@ -293,9 +293,9 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int, edns bool) (
if !ok { if !ok {
return len(msg), false return len(msg), false
} }
case "hex": case "hex":
// TODO need this for DS // TODO need this for DS
println("hex packing not implemented") println("hex packing not implemented")
case "": case "":
// Counted string: 1 byte length. // Counted string: 1 byte length.
if len(s) > 255 || off+1+len(s) > len(msg) { 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: BadType:
fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type) fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
return len(msg), false, false return len(msg), false, false
case *reflect.BoolValue: case *reflect.BoolValue:
// Used internally for Edns, not present in the DNS // Used internally for Edns, not present in the DNS
continue; continue
case *reflect.SliceValue: case *reflect.SliceValue:
switch f.Tag { switch f.Tag {
default: default:
@ -356,8 +356,8 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
b := net.IP(p) b := net.IP(p)
fv.Set(reflect.NewValue(b).(*reflect.SliceValue)) fv.Set(reflect.NewValue(b).(*reflect.SliceValue))
off += net.IPv6len off += net.IPv6len
case "OPT": // edns case "OPT": // edns
// do it here // do it here
} }
case *reflect.StructValue: case *reflect.StructValue:
off, ok, edns = unpackStructValue(fv, msg, off) 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() { switch val.Type().Name() {
case "RR_DS": case "RR_DS":
consumed = 4 // KeyTag(2) + Algorithm(1) + DigestType(1) consumed = 4 // KeyTag(2) + Algorithm(1) + DigestType(1)
default: default:
consumed = 0 // TODO consumed = 0 // TODO
} }
s = hex.EncodeToString(msg[off : off+rdlength-consumed]) 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) consumed = 4 // Flags(2) + Protocol(1) + Algorithm(1)
case "RR_RRSIG": case "RR_RRSIG":
consumed = 18 // TypeCovered(2) + Algorithm(1) + Labels(1) + 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) // Should already be set in the sequence of parsing (comes before)
// Work because of rfc4034, section 3.17 // Work because of rfc4034, section 3.17
consumed += len(val.FieldByName("SignerName").(*reflect.StringValue).Get()) + 1 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. // a bit inefficient but this doesn't need to be fast.
// off1 is end of header // off1 is end of header
// off2 is end of rr // off2 is end of rr
edns := rr.Header().Edns edns := rr.Header().Edns
off1, ok = packStruct(rr.Header(), msg, off, edns) off1, ok = packStruct(rr.Header(), msg, off, edns)
off2, ok = packStruct(rr, msg, off, edns) off2, ok = packStruct(rr, msg, off, edns)
if !ok { if !ok {
@ -506,25 +506,25 @@ func packRR(rr RR, msg []byte, off int) (off2 int, ok bool) {
// Resource record unpacker. // Resource record unpacker.
func unpackRR(msg []byte, off int) (rr RR, off1 int, ok bool) { func unpackRR(msg []byte, off int) (rr RR, off1 int, ok bool) {
// unpack just the header, to find the rr type and length // 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 h RR_Header
var edns bool var edns bool
off0 := off off0 := off
if off, ok, edns = unpackStruct(&h, msg, off); !ok { if off, ok, edns = unpackStruct(&h, msg, off); !ok {
return nil, len(msg), false return nil, len(msg), false
} }
h.Edns = edns // set Edns if found h.Edns = edns // set Edns if found
end := off + int(h.Rdlength) end := off + int(h.Rdlength)
// make an rr of that type and re-unpack. // make an rr of that type and re-unpack.
// again inefficient but doesn't need to be fast. // again inefficient but doesn't need to be fast.
mk, known := rr_mk[int(h.Rrtype)] mk, known := rr_mk[int(h.Rrtype)]
if !known { if !known {
return &h, end, true // false, or unknown RR?? return &h, end, true // false, or unknown RR??
} }
rr = mk() 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 { if off != end {
// added MG // added MG
// println("Hier gaat het dan fout, echt waar en was if off0", off0) // println("Hier gaat het dan fout, echt waar en was if off0", off0)
@ -545,7 +545,7 @@ type MsgHdr struct {
Truncated bool Truncated bool
Recursion_desired bool Recursion_desired bool
Recursion_available bool Recursion_available bool
Z bool // or just zero?? Z bool // or just zero??
Authenticated_data bool Authenticated_data bool
Checking_disabled bool Checking_disabled bool
Rcode int Rcode int
@ -598,7 +598,7 @@ type Msg struct {
Answer []RR Answer []RR
Ns []RR Ns []RR
// EDNS0 has to be put in this section // 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, // Could work harder to calculate message size,
// but this is far more than we need and not // but this is far more than we need and not
// big enough to hurt the allocator. // 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. // Pack it in: header and then the pieces.
off := 0 off := 0

51
resolverEdns_test.go Normal file
View File

@ -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)
}

View File

@ -120,7 +120,7 @@ func (q *Question) String() string {
// There are many types of messages, // There are many types of messages,
// but they all share the same header. // but they all share the same header.
type RR_Header struct { type RR_Header struct {
Edns bool // true is this a edns header Edns bool // true is this a edns header
Name string "domain-name" Name string "domain-name"
Rrtype uint16 Rrtype uint16
Class uint16 Class uint16
@ -134,14 +134,19 @@ func (h *RR_Header) Header() *RR_Header {
func (h *RR_Header) String() string { func (h *RR_Header) String() string {
var s string var s string
if len(h.Name) == 0 {
s = ".\t" if h.Edns {
} else { s = ";"
s = h.Name + "\t" }
}
s = s + strconv.Itoa(int(h.Ttl)) + "\t" if len(h.Name) == 0 {
s = s + class_str[h.Class] + "\t" s += ".\t"
s = s + rr_str[h.Rrtype] + "\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 return s
} }
@ -354,16 +359,16 @@ func (rr *RR_AAAA) String() string {
// DNSSEC types // DNSSEC types
type RR_RRSIG struct { type RR_RRSIG struct {
Hdr RR_Header Hdr RR_Header
TypeCovered uint16 TypeCovered uint16
Algorithm uint8 Algorithm uint8
Labels uint8 Labels uint8
OrigTtl uint32 OrigTtl uint32
Expiration uint32 Expiration uint32
Inception uint32 Inception uint32
KeyTag uint16 KeyTag uint16
SignerName string "domain-name" SignerName string "domain-name"
Sig string "base64" Sig string "base64"
} }
func (rr *RR_RRSIG) Header() *RR_Header { func (rr *RR_RRSIG) Header() *RR_Header {
@ -376,8 +381,8 @@ func (rr *RR_RRSIG) Header() *RR_Header {
// needs serial stuff // needs serial stuff
// starts when 1970 has been 68 years ago?? // starts when 1970 has been 68 years ago??
func intToDate(t uint32) string { func intToDate(t uint32) string {
// als meer dan 68 jaar geleden, dan 68 jaar bij bedrag optellen // als meer dan 68 jaar geleden, dan 68 jaar bij bedrag optellen
// TODO // TODO
ti := time.SecondsToUTC(int64(t)) ti := time.SecondsToUTC(int64(t))
return ti.Format("20060102030405") return ti.Format("20060102030405")
} }
@ -389,9 +394,9 @@ func (rr *RR_RRSIG) String() string {
" " + strconv.Itoa(int(rr.Algorithm)) + " " + strconv.Itoa(int(rr.Algorithm)) +
" " + strconv.Itoa(int(rr.Labels)) + " " + strconv.Itoa(int(rr.Labels)) +
" " + strconv.Itoa(int(rr.OrigTtl)) + " " + strconv.Itoa(int(rr.OrigTtl)) +
// " " + strconv.Itoa(int(rr.Expiration)) + // date calc! TODO // " " + strconv.Itoa(int(rr.Expiration)) + // date calc! TODO
" " + intToDate(rr.Expiration) + " " + intToDate(rr.Expiration) +
// " " + strconv.Itoa(int(rr.Inception)) + // date calc! TODO // " " + strconv.Itoa(int(rr.Inception)) + // date calc! TODO
" " + intToDate(rr.Inception) + " " + intToDate(rr.Inception) +
" " + strconv.Itoa(int(rr.KeyTag)) + " " + strconv.Itoa(int(rr.KeyTag)) +
" " + rr.SignerName + " " + rr.SignerName +
@ -515,7 +520,7 @@ var rr_str = map[uint16]string{
TypeSRV: "SRV", TypeSRV: "SRV",
TypeA: "A", TypeA: "A",
TypeAAAA: "AAAA", TypeAAAA: "AAAA",
TypeOPT: "OPT", TypeOPT: "OPT",
TypeDS: "DS", TypeDS: "DS",
TypeRRSIG: "RRSIG", TypeRRSIG: "RRSIG",
TypeNSEC: "NSEC", TypeNSEC: "NSEC",