Example #1
0
func TestSimple(t *testing.T) {
	conn, err := dns.DialTimeout("udp", dnsToGrpcAddr, 1*time.Second)
	if err != nil {
		t.Fatalf("dns.Dial error: %v", err)
	}
	defer conn.Close()

	err = dnsQuery(conn)
	if err != nil {
		t.Errorf("dns query returned error: %v", err)
	}
}
Example #2
0
func manyDNSQueries(b *testing.B, addr string) {
	conn, err := dns.DialTimeout("udp", addr, 1*time.Second)
	if err != nil {
		b.Fatalf("dns.Dial error: %v", err)
	}
	defer conn.Close()

	for i := 0; i < b.N; i++ {
		err = dnsQuery(conn)
		if err != nil {
			b.Errorf("dns query returned error: %v", err)
		}
	}
}
Example #3
0
func pollServer() {
	backoff := time.Duration(200 * time.Millisecond)
	ctx, _ := context.WithTimeout(context.Background(), time.Duration(5*time.Second))
	ticker := time.NewTicker(backoff)

	for {
		select {
		case <-ctx.Done():
			fmt.Fprintln(os.Stderr, "Timeout reached while testing for the dns server to come up")
			os.Exit(1)
		case <-ticker.C:
			conn, _ := dns.DialTimeout("tcp", dnsLoopbackAddr, backoff)
			if conn != nil {
				_ = conn.Close()
				return
			}
		}
	}
}
Example #4
0
// WaitForDNSServer waits 5 seconds for a DNS server to start, and returns an
// error if it fails to do so.
// It does this by repeatedly querying the DNS server until it either replies
// or times out. Note we do not do any validation of the reply.
func WaitForDNSServer(addr string) error {
	conn, err := dns.DialTimeout("udp", addr, 1*time.Second)
	if err != nil {
		return fmt.Errorf("dns.Dial error: %v", err)
	}
	defer conn.Close()

	m := &dns.Msg{}
	m.SetQuestion("unused.", dns.TypeA)

	deadline := time.Now().Add(5 * time.Second)
	tick := time.Tick(100 * time.Millisecond)

	for (<-tick).Before(deadline) {
		conn.SetDeadline(time.Now().Add(1 * time.Second))
		conn.WriteMsg(m)
		_, err := conn.ReadMsg()
		if err == nil {
			return nil
		}
	}

	return fmt.Errorf("timed out")
}
func (this ClientProxy) ServeDNS(w dns.ResponseWriter, request *dns.Msg) {
	// if we don't have EDNS0 in the packet, add it now
	// TODO: in principle we should check packet size here, since we have made it bigger,
	//       but for this demo code we will just rely on most queries being really small
	proxy_req := *request
	opt := proxy_req.IsEdns0()
	var client_buf_size uint16
	if opt == nil {
		proxy_req.SetEdns0(512, false)
		client_buf_size = 512
		_D("%s QID:%d adding EDNS0 to packet", w.RemoteAddr(), request.Id)
		opt = proxy_req.IsEdns0()
	} else {
		client_buf_size = opt.UDPSize()
	}

	// add our custom EDNS0 option
	local_opt := new(dns.EDNS0_LOCAL)
	local_opt.Code = dns.EDNS0LOCALSTART
	opt.Option = append(opt.Option, local_opt)

	// create a connection to the server
	// XXX: for now we will only handle UDP - this will break in unpredictable ways in production!
	conn, err := dns.DialTimeout("udp", this.SERVERS[rand.Intn(len(this.SERVERS))], this.timeout)
	if err != nil {
		_D("%s QID:%d error setting up UDP socket: %s", w.RemoteAddr(), request.Id, err)
		SRVFAIL(w, request)
		return
	}
	defer conn.Close()

	// set our timeouts
	// TODO: we need to insure that our timeouts work like we expect
	conn.SetReadDeadline(time.Now().Add(this.timeout))
	conn.SetWriteDeadline(time.Now().Add(this.timeout))

	// send our query
	err = conn.WriteMsg(&proxy_req)
	if err != nil {
		_D("%s QID:%d error writing message: %s", w.RemoteAddr(), request.Id, err)
		SRVFAIL(w, request)
		return
	}

	// wait for our reply
	response := wait_for_response(w, conn, request)
	if response == nil {
		return
	}

	// get fragment information from first response (if any)
	num_frags, sequence_num := get_fragment_info(response)

	// if we did not have a fragmented response, send it to the client
	if num_frags == -1 {
		w.WriteMsg(response)
		return
	}

	// build a map to hold the fragments that we have received
	frags := map[int]dns.Msg{sequence_num: *response}

	// wait for all fragments to arrive
	// duplicates overwrite previous packet, missing packets eventually timeout
	for len(frags) < num_frags {
		response := wait_for_response(w, conn, request)
		if response == nil {
			return
		}
		_, sequence_num := get_fragment_info(response)
		// TODO: remove the extra EDNS0 option
		frags[sequence_num] = *response
	}

	// rebuild our original packet
	rebuilt_reply, ok := frags[0]
	if !ok {
		_D("%s QID:%d missing fragment 0", w.RemoteAddr(), request.Id)
		SRVFAIL(w, request)
		return
	}
	for n := 1; n < num_frags; n++ {
		frag, ok := frags[n]
		if !ok {
			_D("%s QID:%d missing fragment %d", w.RemoteAddr(), request.Id, n)
			SRVFAIL(w, request)
			return
		}
		rebuilt_reply.Answer = append(rebuilt_reply.Answer, frag.Answer...)
		rebuilt_reply.Ns = append(rebuilt_reply.Ns, frag.Ns...)
		for _, r := range frag.Extra {
			// remove EDNS0 present in fragments from final answer
			if r.Header().Rrtype != dns.TypeOPT {
				rebuilt_reply.Extra = append(rebuilt_reply.Extra, r)
			}
		}
	}

	// verify that we don't exceed the client buffer size
	if rebuilt_reply.Len() > int(client_buf_size) {
		// truncate if we need to
		// TODO: test this
		rebuilt_reply.MsgHdr.Truncated = true
		rebuilt_reply.Answer = []dns.RR{}
		rebuilt_reply.Ns = []dns.RR{}
		rebuilt_reply.Extra = []dns.RR{}
	}

	// send our rebuilt reply
	w.WriteMsg(&rebuilt_reply)
}