s += "."
}
+ // Allow root domain.
+ if s == "." {
+ msg[off] = 0
+ off++
+ 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.
if i-begin >= 1<<6 { // top two bits of length must be clear
return len(msg), false
}
+ if i-begin == 0 {
+ return len(msg), false
+ }
+
msg[off] = byte(i - begin)
off++
+
for j := begin; j < i; j++ {
msg[off] = s[j]
off++
return "", len(msg), false
}
}
+ if len(s) == 0 {
+ s = "."
+ }
if ptr == 0 {
off1 = off
}
// Pack it in: header and then the pieces.
off := 0
off, ok = packStruct(&dh, msg, off)
+ if !ok {
+ return nil, false
+ }
for i := 0; i < len(question); i++ {
off, ok = packStruct(&question[i], msg, off)
+ if !ok {
+ return nil, false
+ }
}
for i := 0; i < len(answer); i++ {
off, ok = packRR(answer[i], msg, off)
+ if !ok {
+ return nil, false
+ }
}
for i := 0; i < len(ns); i++ {
off, ok = packRR(ns[i], msg, off)
+ if !ok {
+ return nil, false
+ }
}
for i := 0; i < len(extra); i++ {
off, ok = packRR(extra[i], msg, off)
- }
- if !ok {
- return nil, false
+ if !ok {
+ return nil, false
+ }
}
return msg[0:off], true
}
for i := 0; i < len(dns.question); i++ {
off, ok = unpackStruct(&dns.question[i], msg, off)
+ if !ok {
+ return false
+ }
}
for i := 0; i < int(dh.Ancount); i++ {
rec, off, ok = unpackRR(msg, off)
"testing"
)
+func TestStructPackUnpack(t *testing.T) {
+ want := dnsQuestion{
+ Name: ".",
+ Qtype: dnsTypeA,
+ Qclass: dnsClassINET,
+ }
+ buf := make([]byte, 50)
+ n, ok := packStruct(&want, buf, 0)
+ if !ok {
+ t.Fatal("packing failed")
+ }
+ buf = buf[:n]
+ got := dnsQuestion{}
+ n, ok = unpackStruct(&got, buf, 0)
+ if !ok {
+ t.Fatal("unpacking failed")
+ }
+ if n != len(buf) {
+ t.Error("unpacked different amount than packed: got n = %d, want = %d", n, len(buf))
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("got = %+v, want = %+v", got, want)
+ }
+}
+
+func TestDomainNamePackUnpack(t *testing.T) {
+ tests := []struct {
+ in string
+ want string
+ ok bool
+ }{
+ {"", ".", true},
+ {".", ".", true},
+ {"google..com", "", false},
+ {"google.com", "google.com.", true},
+ {"google..com.", "", false},
+ {"google.com.", "google.com.", true},
+ {".google.com.", "", false},
+ {"www..google.com.", "", false},
+ {"www.google.com.", "www.google.com.", true},
+ }
+
+ for _, test := range tests {
+ buf := make([]byte, 30)
+ n, ok := packDomainName(test.in, buf, 0)
+ if ok != test.ok {
+ t.Errorf("packing of %s: got ok = %t, want = %t", test.in, ok, test.ok)
+ continue
+ }
+ if !test.ok {
+ continue
+ }
+ buf = buf[:n]
+ got, n, ok := unpackDomainName(buf, 0)
+ if !ok {
+ t.Errorf("unpacking for %s failed", test.in)
+ continue
+ }
+ if n != len(buf) {
+ t.Error(
+ "unpacked different amount than packed for %s: got n = %d, want = %d",
+ test.in,
+ n,
+ len(buf),
+ )
+ }
+ if got != test.want {
+ t.Errorf("unpacking packing of %s: got = %s, want = %s", test.in, got, test.want)
+ }
+ }
+}
+
+func TestDNSPackUnpack(t *testing.T) {
+ want := dnsMsg{
+ question: []dnsQuestion{{
+ Name: ".",
+ Qtype: dnsTypeAAAA,
+ Qclass: dnsClassINET,
+ }},
+ answer: []dnsRR{},
+ ns: []dnsRR{},
+ extra: []dnsRR{},
+ }
+ b, ok := want.Pack()
+ if !ok {
+ t.Fatal("packing failed")
+ }
+ var got dnsMsg
+ ok = got.Unpack(b)
+ if !ok {
+ t.Fatal("unpacking failed")
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("got = %+v, want = %+v", got, want)
+ }
+}
+
func TestDNSParseSRVReply(t *testing.T) {
data, err := hex.DecodeString(dnsSRVReply)
if err != nil {