Skip to content
Snippets Groups Projects
Select Git revision
  • c13035a344de8f19b626f171eb429f3d97c630bf
  • master default protected
  • client_certs
  • v1.0
  • v0.8
  • v0.7.2
  • v0.7.1
  • v0.7
  • v0.6
  • v0.5
  • v0.4
  • v0.3.2
  • v0.3.1
  • v0.3
  • v0.2
  • v0.1
16 results

dns_test.go

Blame
  • user avatar
    znerol authored and Joona Hoikkala committed
    The DB.Update function takes a type of ACMETxt. However, the function
    only requires the Value and Subdomain fields.
    
    Refactor the function such that it takes ACMETxtPost instead of the full
    ACMETxt record. This will simplify extraction of txt-record related
    logic from the db code.
    c13035a3
    History
    dns_test.go 6.93 KiB
    package main
    
    import (
    	"database/sql"
    	"database/sql/driver"
    	"errors"
    	"fmt"
    	"testing"
    
    	"github.com/erikstmartin/go-testdb"
    	"github.com/miekg/dns"
    )
    
    var resolv resolver
    var server *dns.Server
    
    type resolver struct {
    	server string
    }
    
    func (r *resolver) lookup(host string, qtype uint16) (*dns.Msg, error) {
    	msg := new(dns.Msg)
    	msg.Id = dns.Id()
    	msg.Question = make([]dns.Question, 1)
    	msg.Question[0] = dns.Question{Name: dns.Fqdn(host), Qtype: qtype, Qclass: dns.ClassINET}
    	in, err := dns.Exchange(msg, r.server)
    	if err != nil {
    		return in, fmt.Errorf("Error querying the server [%v]", err)
    	}
    	if in != nil && in.Rcode != dns.RcodeSuccess {
    		return in, fmt.Errorf("Received error from the server [%s]", dns.RcodeToString[in.Rcode])
    	}
    
    	return in, nil
    }
    
    func hasExpectedTXTAnswer(answer []dns.RR, cmpTXT string) error {
    	for _, record := range answer {
    		// We expect only one answer, so no need to loop through the answer slice
    		if rec, ok := record.(*dns.TXT); ok {
    			for _, txtValue := range rec.Txt {
    				if txtValue == cmpTXT {
    					return nil
    				}
    			}
    		} else {
    			errmsg := fmt.Sprintf("Got answer of unexpected type [%q]", answer[0])
    			return errors.New(errmsg)
    		}
    	}
    	return errors.New("Expected answer not found")
    }
    
    func TestQuestionDBError(t *testing.T) {
    	testdb.SetQueryWithArgsFunc(func(query string, args []driver.Value) (result driver.Rows, err error) {
    		columns := []string{"Username", "Password", "Subdomain", "Value", "LastActive"}
    		return testdb.RowsFromSlice(columns, [][]driver.Value{}), errors.New("Prepared query error")
    	})
    
    	defer testdb.Reset()
    
    	tdb, err := sql.Open("testdb", "")
    	if err != nil {
    		t.Errorf("Got error: %v", err)
    	}
    	oldDb := DB.GetBackend()
    
    	DB.SetBackend(tdb)
    	defer DB.SetBackend(oldDb)
    
    	q := dns.Question{Name: dns.Fqdn("whatever.tld"), Qtype: dns.TypeTXT, Qclass: dns.ClassINET}
    	_, err = dnsserver.answerTXT(q)
    	if err == nil {
    		t.Errorf("Expected error but got none")
    	}
    }
    
    func TestParse(t *testing.T) {
    	var testcfg = DNSConfig{
    		General: general{
    			Domain:        ")",
    			Nsname:        "ns1.auth.example.org",
    			Nsadmin:       "admin.example.org",
    			StaticRecords: []string{},
    			Debug:         false,
    		},
    	}
    	dnsserver.ParseRecords(testcfg)
    	if !loggerHasEntryWithMessage("Error while adding SOA record") {
    		t.Errorf("Expected SOA parsing to return error, but did not find one")
    	}
    }
    
    func TestResolveA(t *testing.T) {
    	resolv := resolver{server: "127.0.0.1:15353"}
    	answer, err := resolv.lookup("auth.example.org", dns.TypeA)
    	if err != nil {
    		t.Errorf("%v", err)
    	}
    
    	if len(answer.Answer) == 0 {
    		t.Error("No answer for DNS query")
    	}
    
    	_, err = resolv.lookup("nonexistent.domain.tld", dns.TypeA)
    	if err == nil {
    		t.Errorf("Was expecting error because of NXDOMAIN but got none")
    	}
    }
    
    func TestEDNS(t *testing.T) {
    	resolv := resolver{server: "127.0.0.1:15353"}
    	answer, _ := resolv.lookup("auth.example.org", dns.TypeOPT)
    	if answer.Rcode != dns.RcodeFormatError {
    		t.Errorf("Was expecing FORMERR rcode for OPT query, but got [%s] instead.", dns.RcodeToString[answer.Rcode])
    	}
    }
    
    func TestResolveCNAME(t *testing.T) {
    	resolv := resolver{server: "127.0.0.1:15353"}
    	expected := "cn.example.org.	3600	IN	CNAME	something.example.org."
    	answer, err := resolv.lookup("cn.example.org", dns.TypeCNAME)
    	if err != nil {
    		t.Errorf("Got unexpected error: %s", err)
    	}
    	if len(answer.Answer) != 1 {
    		t.Errorf("Expected exactly 1 RR in answer, but got %d instead.", len(answer.Answer))
    	}
    	if answer.Answer[0].Header().Rrtype != dns.TypeCNAME {
    		t.Errorf("Expected a CNAME answer, but got [%s] instead.", dns.TypeToString[answer.Answer[0].Header().Rrtype])
    	}
    	if answer.Answer[0].String() != expected {
    		t.Errorf("Expected CNAME answer [%s] but got [%s] instead.", expected, answer.Answer[0].String())
    	}
    }
    
    func TestAuthoritative(t *testing.T) {
    	resolv := resolver{server: "127.0.0.1:15353"}
    	answer, _ := resolv.lookup("nonexistent.auth.example.org", dns.TypeA)
    	if answer.Rcode != dns.RcodeNameError {
    		t.Errorf("Was expecing NXDOMAIN rcode, but got [%s] instead.", dns.RcodeToString[answer.Rcode])
    	}
    	if len(answer.Ns) != 1 {
    		t.Errorf("Was expecting exactly one answer (SOA) for invalid subdomain, but got %d", len(answer.Ns))
    	}
    	if answer.Ns[0].Header().Rrtype != dns.TypeSOA {
    		t.Errorf("Was expecting SOA record as answer for NXDOMAIN but got [%s]", dns.TypeToString[answer.Ns[0].Header().Rrtype])
    	}
    	if !answer.MsgHdr.Authoritative {
    		t.Errorf("Was expecting authoritative bit to be set")
    	}
    	nanswer, _ := resolv.lookup("nonexsitent.nonauth.tld", dns.TypeA)
    	if len(nanswer.Answer) > 0 {
    		t.Errorf("Didn't expect answers for non authotitative domain query")
    	}
    	if nanswer.MsgHdr.Authoritative {
    		t.Errorf("Authoritative bit should not be set for non-authoritative domain.")
    	}
    }
    
    func TestResolveTXT(t *testing.T) {
    	resolv := resolver{server: "127.0.0.1:15353"}
    	validTXT := "______________valid_response_______________"
    
    	atxt, err := DB.Register(cidrslice{})
    	if err != nil {
    		t.Errorf("Could not initiate db record: [%v]", err)
    		return
    	}
    	atxt.Value = validTXT
    	err = DB.Update(atxt.ACMETxtPost)
    	if err != nil {
    		t.Errorf("Could not update db record: [%v]", err)
    		return
    	}
    
    	for i, test := range []struct {
    		subDomain   string
    		expTXT      string
    		getAnswer   bool
    		validAnswer bool
    	}{
    		{atxt.Subdomain, validTXT, true, true},
    		{atxt.Subdomain, "invalid", true, false},
    		{"a097455b-52cc-4569-90c8-7a4b97c6eba8", validTXT, false, false},
    	} {
    		answer, err := resolv.lookup(test.subDomain+".auth.example.org", dns.TypeTXT)
    		if err != nil {
    			if test.getAnswer {
    				t.Fatalf("Test %d: Expected answer but got: %v", i, err)
    			}
    		} else {
    			if !test.getAnswer {
    				t.Errorf("Test %d: Expected no answer, but got one.", i)
    			}
    		}
    
    		if len(answer.Answer) > 0 {
    			if !test.getAnswer && answer.Answer[0].Header().Rrtype != dns.TypeSOA {
    				t.Errorf("Test %d: Expected no answer, but got: [%q]", i, answer)
    			}
    			if test.getAnswer {
    				err = hasExpectedTXTAnswer(answer.Answer, test.expTXT)
    				if err != nil {
    					if test.validAnswer {
    						t.Errorf("Test %d: %v", i, err)
    					}
    				} else {
    					if !test.validAnswer {
    						t.Errorf("Test %d: Answer was not expected to be valid, answer [%q], compared to [%s]", i, answer, test.expTXT)
    					}
    				}
    			}
    		} else {
    			if test.getAnswer {
    				t.Errorf("Test %d: Expected answer, but didn't get one", i)
    			}
    		}
    	}
    }
    
    func TestCaseInsensitiveResolveA(t *testing.T) {
      resolv := resolver{server: "127.0.0.1:15353"}
      answer, err := resolv.lookup("aUtH.eXAmpLe.org", dns.TypeA)
      if err != nil {
        t.Errorf("%v", err)
      }
    
      if len(answer.Answer) == 0 {
        t.Error("No answer for DNS query")
      }
    }
    
    func TestCaseInsensitiveResolveSOA(t *testing.T) {
      resolv := resolver{server: "127.0.0.1:15353"}
      answer, _ := resolv.lookup("doesnotexist.aUtH.eXAmpLe.org", dns.TypeSOA)
      if answer.Rcode != dns.RcodeNameError {
        t.Errorf("Was expecing NXDOMAIN rcode, but got [%s] instead.", dns.RcodeToString[answer.Rcode])
      }
    
      if len(answer.Ns) == 0 {
        t.Error("No SOA answer for DNS query")
      }
    }