github.com/elfadel/cilium@v1.6.12/pkg/fqdn/lookup_test.go (about)

     1  // Copyright 2018 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // +build !privileged_tests
    16  
    17  package fqdn
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"net"
    23  
    24  	"github.com/miekg/dns"
    25  
    26  	. "gopkg.in/check.v1"
    27  )
    28  
    29  func init() {
    30  	// setup dummy dnsConfig for tests
    31  	dnsConfig = &dns.ClientConfig{
    32  		Servers:  []string{"1.2.3.4", "5.6.7.8"},
    33  		Search:   make([]string, 0),
    34  		Port:     "53",
    35  		Ndots:    1,
    36  		Timeout:  5,
    37  		Attempts: 2,
    38  	}
    39  }
    40  
    41  func makeResponse(qname string, dnsType uint16, rcode int, answers []dns.RR) *dns.Msg {
    42  	ret := &dns.Msg{}
    43  	ret.SetQuestion(dns.Fqdn(qname), dnsType)
    44  	ret.Opcode = dns.OpcodeQuery
    45  	ret.Rcode = rcode
    46  	ret.RecursionDesired = true
    47  	ret.RecursionAvailable = true
    48  	ret.Response = true
    49  	ret.Answer = answers
    50  	return ret
    51  }
    52  
    53  // TestDNSResolverQueryAllNames tests that DNSLookupDefaultResolver should:
    54  // - query all names in dnsNames
    55  // - query for A and AAAA for each name
    56  // - use the TTL in CNAMEs to set the TTL, and choose the lowest
    57  func (ds *FQDNTestSuite) TestDNSResolverQueryAllNames(c *C) {
    58  	dnsNames := []string{"a.com", "b.com", "c.com"}
    59  
    60  	lookups := make(map[string]int)
    61  	lookupFunc := func(server string, name string, dnsType uint16) (response *dns.Msg, err error) {
    62  		lookups[name]++
    63  		switch dnsType {
    64  		case dns.TypeA:
    65  			return makeResponse(name, dnsType, dns.RcodeSuccess, []dns.RR{
    66  				&dns.CNAME{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: 20}, Target: "something.else."},
    67  				&dns.A{Hdr: dns.RR_Header{Name: "something.else.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 60}, A: net.ParseIP("1.1.1.1")},
    68  				&dns.A{Hdr: dns.RR_Header{Name: "something.else.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 60}, A: net.ParseIP("2.2.2.2")},
    69  			}), nil
    70  		case dns.TypeAAAA:
    71  			return makeResponse(name, dnsType, dns.RcodeSuccess, []dns.RR{
    72  				&dns.CNAME{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: 10}, Target: "something.else."},
    73  				&dns.AAAA{Hdr: dns.RR_Header{Name: "something.else.", Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 60}, AAAA: net.ParseIP("cafe::face")},
    74  				&dns.AAAA{Hdr: dns.RR_Header{Name: "something.else.", Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 60}, AAAA: net.ParseIP("face::cafe")},
    75  			}), nil
    76  
    77  		default:
    78  			return makeResponse(name, dnsType, dns.RcodeRefused, nil), nil
    79  		}
    80  	}
    81  
    82  	responses, errors := doResolverLogic(lookupFunc, dnsNames)
    83  	c.Assert(len(errors), Equals, 0, Commentf("Returned unexpected errors for some names: %v", errors))
    84  	c.Assert(len(responses), Equals, len(dnsNames), Commentf("Did not return results for all query names"))
    85  	c.Assert(len(lookups), Equals, len(dnsNames), Commentf("Did not do a lookup for all names"))
    86  	for name, ans := range responses {
    87  		c.Assert(lookups[name], Equals, 2, Commentf("More than 2 expected lookups (A & AAAA) for %s: %v", name, lookups))
    88  
    89  		c.Assert(len(ans.IPs), Equals, 4, Commentf("Incorrect number of IPs returned from lookups"))
    90  		for i, correctIP := range []string{"1.1.1.1", "2.2.2.2", "cafe::face", "face::cafe"} {
    91  			c.Assert(ans.IPs[i].String(), Equals, correctIP, Commentf("Incorrect IP returned"))
    92  		}
    93  
    94  		c.Assert(ans.TTL, Equals, 10, Commentf("TTL is not the smallest of all A, AAAA, and CNAME records"))
    95  	}
    96  }
    97  
    98  // TestDNSResolverNextServerOnError tests that DNSLookupDefaultResolver should:
    99  // test that we skip to next server on error
   100  func (ds *FQDNTestSuite) TestDNSResolverNextServerOnError(c *C) {
   101  	dnsNames := []string{"a.com"}
   102  
   103  	lookups := make(map[string]int)
   104  	lookupFunc := func(server string, name string, dnsType uint16) (response *dns.Msg, err error) {
   105  		lookups[server]++
   106  
   107  		// Return an error on the first lookup, then work correctly
   108  		if len(lookups) == 1 {
   109  			return nil, errors.New("test error")
   110  
   111  		}
   112  
   113  		switch dnsType {
   114  		case dns.TypeA:
   115  			return makeResponse(name, dnsType, dns.RcodeSuccess, []dns.RR{
   116  				&dns.A{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 30}, A: net.ParseIP("1.1.1.1")},
   117  				&dns.A{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 30}, A: net.ParseIP("2.2.2.2")},
   118  			}), nil
   119  		case dns.TypeAAAA:
   120  			return makeResponse(name, dnsType, dns.RcodeSuccess, []dns.RR{
   121  				&dns.AAAA{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 60}, AAAA: net.ParseIP("cafe::face")},
   122  				&dns.AAAA{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 60}, AAAA: net.ParseIP("face::cafe")},
   123  			}), nil
   124  		}
   125  
   126  		return nil, fmt.Errorf("Unhandled DNS query type: %v", dnsType)
   127  	}
   128  
   129  	responses, errors := doResolverLogic(lookupFunc, dnsNames)
   130  	c.Assert(len(errors), Equals, 0, Commentf("Returned incorrect number of errors(cleared on success): %v", errors))
   131  	c.Assert(len(lookups), Equals, len(dnsConfig.Servers), Commentf("Did not query 2/2 DNS servers (expected due to test-induced error): %v", lookups))
   132  	c.Assert(lookups[dnsConfig.Servers[0]+":"+dnsConfig.Port], Equals, 2, Commentf("First server in list not queried enough times (1 error, 1 success): %v", lookups))
   133  	c.Assert(lookups[dnsConfig.Servers[1]+":"+dnsConfig.Port], Equals, 1, Commentf("Second server in list not queried enough times (1 success from failover): %v", lookups))
   134  	for _, ans := range responses {
   135  		c.Assert(len(ans.IPs), Equals, 4, Commentf("Incorrect number of IPs returned from lookups"))
   136  		for i, correctIP := range []string{"1.1.1.1", "2.2.2.2", "cafe::face", "face::cafe"} {
   137  			c.Assert(ans.IPs[i].String(), Equals, correctIP, Commentf("Incorrect IP returned"))
   138  		}
   139  
   140  		c.Assert(ans.TTL, Equals, 30, Commentf("TTL is not the smallest of all A, AAAA, and CNAME records"))
   141  	}
   142  
   143  }