package dns import ( "strconv" "testing" "time" ) func TestClientSync(t *testing.T) { HandleFunc("miek.nl.", HelloServer) defer HandleRemove("miek.nl.") s, addrstr, err := RunLocalUDPServer("127.0.0.1:0") if err != nil { t.Fatalf("Unable to run test server: %v", err) } defer s.Shutdown() m := new(Msg) m.SetQuestion("miek.nl.", TypeSOA) c := new(Client) r, _, err := c.Exchange(m, addrstr) if err != nil { t.Errorf("failed to exchange: %v", err) } if r != nil && r.Rcode != RcodeSuccess { t.Errorf("failed to get an valid answer\n%v", r) } // And now with plain Exchange(). r, err = Exchange(m, addrstr) if err != nil { t.Errorf("failed to exchange: %v", err) } if r == nil || r.Rcode != RcodeSuccess { t.Errorf("failed to get an valid answer\n%v", r) } } func TestClientSyncBadId(t *testing.T) { HandleFunc("miek.nl.", HelloServerBadId) defer HandleRemove("miek.nl.") s, addrstr, err := RunLocalUDPServer("127.0.0.1:0") if err != nil { t.Fatalf("Unable to run test server: %v", err) } defer s.Shutdown() m := new(Msg) m.SetQuestion("miek.nl.", TypeSOA) c := new(Client) if _, _, err := c.Exchange(m, addrstr); err != ErrId { t.Errorf("did not find a bad Id") } // And now with plain Exchange(). if _, err := Exchange(m, addrstr); err != ErrId { t.Errorf("did not find a bad Id") } } func TestClientEDNS0(t *testing.T) { HandleFunc("miek.nl.", HelloServer) defer HandleRemove("miek.nl.") s, addrstr, err := RunLocalUDPServer("127.0.0.1:0") if err != nil { t.Fatalf("Unable to run test server: %v", err) } defer s.Shutdown() m := new(Msg) m.SetQuestion("miek.nl.", TypeDNSKEY) m.SetEdns0(2048, true) c := new(Client) r, _, err := c.Exchange(m, addrstr) if err != nil { t.Errorf("failed to exchange: %v", err) } if r != nil && r.Rcode != RcodeSuccess { t.Errorf("failed to get an valid answer\n%v", r) } } // Validates the transmission and parsing of local EDNS0 options. func TestClientEDNS0Local(t *testing.T) { optStr1 := "1979:0x0707" optStr2 := strconv.Itoa(EDNS0LOCALSTART) + ":0x0601" handler := func(w ResponseWriter, req *Msg) { m := new(Msg) m.SetReply(req) m.Extra = make([]RR, 1, 2) m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello local edns"}} // If the local options are what we expect, then reflect them back. ec1 := req.Extra[0].(*OPT).Option[0].(*EDNS0_LOCAL).String() ec2 := req.Extra[0].(*OPT).Option[1].(*EDNS0_LOCAL).String() if ec1 == optStr1 && ec2 == optStr2 { m.Extra = append(m.Extra, req.Extra[0]) } w.WriteMsg(m) } HandleFunc("miek.nl.", handler) defer HandleRemove("miek.nl.") s, addrstr, err := RunLocalUDPServer("127.0.0.1:0") if err != nil { t.Fatalf("Unable to run test server: %s", err) } defer s.Shutdown() m := new(Msg) m.SetQuestion("miek.nl.", TypeTXT) // Add two local edns options to the query. ec1 := &EDNS0_LOCAL{Code: 1979, Data: []byte{7, 7}} ec2 := &EDNS0_LOCAL{Code: EDNS0LOCALSTART, Data: []byte{6, 1}} o := &OPT{Hdr: RR_Header{Name: ".", Rrtype: TypeOPT}, Option: []EDNS0{ec1, ec2}} m.Extra = append(m.Extra, o) c := new(Client) r, _, e := c.Exchange(m, addrstr) if e != nil { t.Logf("failed to exchange: %s", e.Error()) t.Fail() } if r != nil && r.Rcode != RcodeSuccess { t.Log("failed to get a valid answer") t.Fail() t.Logf("%v\n", r) } txt := r.Extra[0].(*TXT).Txt[0] if txt != "Hello local edns" { t.Log("Unexpected result for miek.nl", txt, "!= Hello local edns") t.Fail() } // Validate the local options in the reply. got := r.Extra[1].(*OPT).Option[0].(*EDNS0_LOCAL).String() if got != optStr1 { t.Log("failed to get local edns0 answer; got %s, expected %s", got, optStr1) t.Fail() t.Logf("%v\n", r) } got = r.Extra[1].(*OPT).Option[1].(*EDNS0_LOCAL).String() if got != optStr2 { t.Log("failed to get local edns0 answer; got %s, expected %s", got, optStr2) t.Fail() t.Logf("%v\n", r) } } func TestSingleSingleInflight(t *testing.T) { HandleFunc("miek.nl.", HelloServer) defer HandleRemove("miek.nl.") s, addrstr, err := RunLocalUDPServer("127.0.0.1:0") if err != nil { t.Fatalf("Unable to run test server: %v", err) } defer s.Shutdown() m := new(Msg) m.SetQuestion("miek.nl.", TypeDNSKEY) c := new(Client) c.SingleInflight = true nr := 10 ch := make(chan time.Duration) for i := 0; i < nr; i++ { go func() { _, rtt, _ := c.Exchange(m, addrstr) ch <- rtt }() } i := 0 var first time.Duration // With inflight *all* rtt are identical, and by doing actual lookups // the changes that this is a coincidence is small. Loop: for { select { case rtt := <-ch: if i == 0 { first = rtt } else { if first != rtt { t.Errorf("all rtts should be equal. got %d want %d", rtt, first) } } i++ if i == 10 { break Loop } } } } // ExampleUpdateLeaseTSIG shows how to update a lease signed with TSIG. func ExampleUpdateLeaseTSIG(t *testing.T) { m := new(Msg) m.SetUpdate("t.local.ip6.io.") rr, _ := NewRR("t.local.ip6.io. 30 A 127.0.0.1") rrs := make([]RR, 1) rrs[0] = rr m.Insert(rrs) leaseRr := new(OPT) leaseRr.Hdr.Name = "." leaseRr.Hdr.Rrtype = TypeOPT e := new(EDNS0_UL) e.Code = EDNS0UL e.Lease = 120 leaseRr.Option = append(leaseRr.Option, e) m.Extra = append(m.Extra, leaseRr) c := new(Client) m.SetTsig("polvi.", HmacMD5, 300, time.Now().Unix()) c.TsigSecret = map[string]string{"polvi.": "pRZgBrBvI4NAHZYhxmhs/Q=="} _, _, err := c.Exchange(m, "127.0.0.1:53") if err != nil { t.Error(err) } } func TestClientConn(t *testing.T) { HandleFunc("miek.nl.", HelloServer) defer HandleRemove("miek.nl.") // This uses TCP just to make it slightly different than TestClientSync s, addrstr, err := RunLocalTCPServer("127.0.0.1:0") if err != nil { t.Fatalf("Unable to run test server: %v", err) } defer s.Shutdown() m := new(Msg) m.SetQuestion("miek.nl.", TypeSOA) cn, err := Dial("tcp", addrstr) if err != nil { t.Errorf("failed to dial %s: %v", addrstr, err) } err = cn.WriteMsg(m) if err != nil { t.Errorf("failed to exchange: %v", err) } r, err := cn.ReadMsg() if r == nil || r.Rcode != RcodeSuccess { t.Errorf("failed to get an valid answer\n%v", r) } err = cn.WriteMsg(m) if err != nil { t.Errorf("failed to exchange: %v", err) } h := new(Header) buf, err := cn.ReadMsgHeader(h) if buf == nil { t.Errorf("failed to get an valid answer\n%v", r) } if int(h.Bits&0xF) != RcodeSuccess { t.Errorf("failed to get an valid answer in ReadMsgHeader\n%v", r) } if h.Ancount != 0 || h.Qdcount != 1 || h.Nscount != 0 || h.Arcount != 1 { t.Errorf("expected to have question and additional in response; got something else: %+v", h) } if err = r.Unpack(buf); err != nil { t.Errorf("unable to unpack message fully: %v", err) } }