mirror of
https://github.com/wahyd4/cert-manager.git
synced 2026-08-09 21:26:04 +10:00
Refactor test DNS server into separate package
Signed-off-by: James Munnelly <james@munnelly.eu>
This commit is contained in:
@@ -31,10 +31,11 @@ go_test(
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/certmanager/v1alpha1:go_default_library",
|
||||
"//pkg/logs:go_default_library",
|
||||
"//test/acme/dns:go_default_library",
|
||||
"//test/acme/dns/server:go_default_library",
|
||||
"//vendor/github.com/miekg/dns:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -19,25 +19,28 @@ package rfc2136
|
||||
import (
|
||||
"testing"
|
||||
|
||||
dnslib "github.com/miekg/dns"
|
||||
|
||||
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
|
||||
logf "github.com/jetstack/cert-manager/pkg/logs"
|
||||
"github.com/jetstack/cert-manager/test/acme/dns"
|
||||
testserver "github.com/jetstack/cert-manager/test/acme/dns/server"
|
||||
)
|
||||
|
||||
func TestRunSuiteWithTSIG(t *testing.T) {
|
||||
dnslib.HandleFunc(rfc2136TestZone, (&basicStatefulServer{}).serverHandlerPassBackRequest)
|
||||
defer dnslib.HandleRemove(rfc2136TestZone)
|
||||
|
||||
server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", true)
|
||||
if err != nil {
|
||||
t.Errorf("error starting test dns server: %v", err)
|
||||
t.FailNow()
|
||||
ctx := logf.NewContext(nil, nil, t.Name())
|
||||
server := &testserver.BasicServer{
|
||||
Zones: []string{rfc2136TestZone},
|
||||
EnableTSIG: true,
|
||||
TSIGZone: rfc2136TestZone,
|
||||
TSIGKeyName: rfc2136TestTsigKeyName,
|
||||
TSIGKeySecret: rfc2136TestTsigSecret,
|
||||
}
|
||||
if err := server.Run(ctx); err != nil {
|
||||
t.Fatalf("failed to start test server: %v", err)
|
||||
}
|
||||
defer server.Shutdown()
|
||||
|
||||
var validConfig = cmapi.ACMEIssuerDNS01ProviderRFC2136{
|
||||
Nameserver: addrstr,
|
||||
Nameserver: server.ListenAddr(),
|
||||
TSIGSecret: cmapi.SecretKeySelector{
|
||||
LocalObjectReference: cmapi.LocalObjectReference{
|
||||
Name: "testkey",
|
||||
@@ -52,7 +55,7 @@ func TestRunSuiteWithTSIG(t *testing.T) {
|
||||
dns.SetResolvedFQDN(rfc2136TestFqdn),
|
||||
dns.SetAllowAmbientCredentials(false),
|
||||
dns.SetConfig(validConfig),
|
||||
dns.SetDNSServer(addrstr),
|
||||
dns.SetDNSServer(server.ListenAddr()),
|
||||
dns.SetManifestPath("testdata"),
|
||||
// Disable recursive NS lookups as we run a single authoritative NS per test
|
||||
dns.SetUseAuthoritative(false),
|
||||
@@ -62,18 +65,17 @@ func TestRunSuiteWithTSIG(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRunSuiteNoTSIG(t *testing.T) {
|
||||
dnslib.HandleFunc(rfc2136TestZone, (&basicStatefulServer{}).serverHandlerPassBackRequest)
|
||||
defer dnslib.HandleRemove(rfc2136TestZone)
|
||||
|
||||
server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false)
|
||||
if err != nil {
|
||||
t.Errorf("error starting test dns server: %v", err)
|
||||
t.FailNow()
|
||||
ctx := logf.NewContext(nil, nil, t.Name())
|
||||
server := &testserver.BasicServer{
|
||||
Zones: []string{rfc2136TestZone},
|
||||
}
|
||||
if err := server.Run(ctx); err != nil {
|
||||
t.Fatalf("failed to start test server: %v", err)
|
||||
}
|
||||
defer server.Shutdown()
|
||||
|
||||
var validConfig = cmapi.ACMEIssuerDNS01ProviderRFC2136{
|
||||
Nameserver: addrstr,
|
||||
Nameserver: server.ListenAddr(),
|
||||
}
|
||||
|
||||
fixture := dns.NewFixture(&Solver{},
|
||||
@@ -81,7 +83,7 @@ func TestRunSuiteNoTSIG(t *testing.T) {
|
||||
dns.SetResolvedFQDN(rfc2136TestFqdn),
|
||||
dns.SetAllowAmbientCredentials(false),
|
||||
dns.SetConfig(validConfig),
|
||||
dns.SetDNSServer(addrstr),
|
||||
dns.SetDNSServer(server.ListenAddr()),
|
||||
dns.SetManifestPath("testdata"),
|
||||
// Disable recursive NS lookups as we run a single authoritative NS per test
|
||||
dns.SetUseAuthoritative(false),
|
||||
|
||||
@@ -23,15 +23,15 @@ package rfc2136
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/klog"
|
||||
|
||||
logf "github.com/jetstack/cert-manager/pkg/logs"
|
||||
testserver "github.com/jetstack/cert-manager/test/acme/dns/server"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -46,19 +46,20 @@ var (
|
||||
)
|
||||
|
||||
func TestRFC2136CanaryLocalTestServer(t *testing.T) {
|
||||
dns.HandleFunc("example.com.", serverHandlerHello)
|
||||
defer dns.HandleRemove("example.com.")
|
||||
|
||||
server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start test server: %v", err)
|
||||
ctx := logf.NewContext(nil, nil, t.Name())
|
||||
server := &testserver.BasicServer{
|
||||
Zones: []string{rfc2136TestZone},
|
||||
Handler: dns.HandlerFunc(serverHandlerHello),
|
||||
}
|
||||
if err := server.Run(ctx); err != nil {
|
||||
t.Fatalf("failed to start test server: %v", err)
|
||||
}
|
||||
defer server.Shutdown()
|
||||
|
||||
c := new(dns.Client)
|
||||
m := new(dns.Msg)
|
||||
m.SetQuestion("example.com.", dns.TypeTXT)
|
||||
r, _, err := c.Exchange(m, addrstr)
|
||||
r, _, err := c.Exchange(m, server.ListenAddr())
|
||||
if err != nil || len(r.Extra) == 0 {
|
||||
t.Fatalf("Failed to communicate with test server: %v", err)
|
||||
}
|
||||
@@ -69,17 +70,17 @@ func TestRFC2136CanaryLocalTestServer(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRFC2136ServerSuccess(t *testing.T) {
|
||||
dns.HandleFunc(rfc2136TestZone, serverHandlerReturnSuccess)
|
||||
defer dns.HandleRemove(rfc2136TestZone)
|
||||
|
||||
server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start test server: %v", err)
|
||||
ctx := logf.NewContext(nil, nil, t.Name())
|
||||
server := &testserver.BasicServer{
|
||||
Zones: []string{rfc2136TestZone},
|
||||
Handler: dns.HandlerFunc(serverHandlerReturnSuccess),
|
||||
}
|
||||
if err := server.Run(ctx); err != nil {
|
||||
t.Fatalf("failed to start test server: %v", err)
|
||||
}
|
||||
defer server.Shutdown()
|
||||
|
||||
provider, err := NewDNSProviderCredentials(addrstr, "", "", "")
|
||||
provider, err := NewDNSProviderCredentials(server.ListenAddr(), "", "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected NewDNSProviderCredentials() to return no error but the error was -> %v", err)
|
||||
}
|
||||
@@ -89,16 +90,17 @@ func TestRFC2136ServerSuccess(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRFC2136ServerError(t *testing.T) {
|
||||
dns.HandleFunc(rfc2136TestZone, serverHandlerReturnErr)
|
||||
defer dns.HandleRemove(rfc2136TestZone)
|
||||
|
||||
server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start test server: %v", err)
|
||||
ctx := logf.NewContext(nil, nil, t.Name())
|
||||
server := &testserver.BasicServer{
|
||||
Zones: []string{rfc2136TestZone},
|
||||
Handler: dns.HandlerFunc(serverHandlerReturnErr),
|
||||
}
|
||||
if err := server.Run(ctx); err != nil {
|
||||
t.Fatalf("failed to start test server: %v", err)
|
||||
}
|
||||
defer server.Shutdown()
|
||||
|
||||
provider, err := NewDNSProviderCredentials(addrstr, "", "", "")
|
||||
provider, err := NewDNSProviderCredentials(server.ListenAddr(), "", "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected NewDNSProviderCredentials() to return no error but the error was -> %v", err)
|
||||
}
|
||||
@@ -110,16 +112,21 @@ func TestRFC2136ServerError(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRFC2136TsigClient(t *testing.T) {
|
||||
dns.HandleFunc(rfc2136TestZone, serverHandlerReturnSuccess)
|
||||
defer dns.HandleRemove(rfc2136TestZone)
|
||||
|
||||
server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start test server: %v", err)
|
||||
ctx := logf.NewContext(nil, nil, t.Name())
|
||||
server := &testserver.BasicServer{
|
||||
Zones: []string{rfc2136TestZone},
|
||||
Handler: dns.HandlerFunc(serverHandlerReturnSuccess),
|
||||
EnableTSIG: true,
|
||||
TSIGZone: rfc2136TestZone,
|
||||
TSIGKeyName: rfc2136TestTsigKeyName,
|
||||
TSIGKeySecret: rfc2136TestTsigSecret,
|
||||
}
|
||||
if err := server.Run(ctx); err != nil {
|
||||
t.Fatalf("failed to start test server: %v", err)
|
||||
}
|
||||
defer server.Shutdown()
|
||||
|
||||
provider, err := NewDNSProviderCredentials(addrstr, "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret)
|
||||
provider, err := NewDNSProviderCredentials(server.ListenAddr(), "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected NewDNSProviderCredentials() to return no error but the error was -> %v", err)
|
||||
}
|
||||
@@ -206,12 +213,12 @@ func TestRFC2136InvalidTSIGAlgorithm(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRFC2136ValidUpdatePacket(t *testing.T) {
|
||||
dns.HandleFunc(rfc2136TestZone, (&basicStatefulServer{}).serverHandlerPassBackRequest)
|
||||
defer dns.HandleRemove(rfc2136TestZone)
|
||||
|
||||
server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start test server: %v", err)
|
||||
ctx := logf.NewContext(nil, nil, t.Name())
|
||||
server := &testserver.BasicServer{
|
||||
Zones: []string{rfc2136TestZone},
|
||||
}
|
||||
if err := server.Run(ctx); err != nil {
|
||||
t.Fatalf("failed to start test server: %v", err)
|
||||
}
|
||||
defer server.Shutdown()
|
||||
|
||||
@@ -221,13 +228,8 @@ func TestRFC2136ValidUpdatePacket(t *testing.T) {
|
||||
m.SetUpdate(rfc2136TestZone)
|
||||
m.RemoveRRset(rrs)
|
||||
m.Insert(rrs)
|
||||
//expectstr := m.String()
|
||||
//expect, err := m.Pack()
|
||||
if err != nil {
|
||||
t.Fatalf("Error packing expect msg: %v", err)
|
||||
}
|
||||
|
||||
provider, err := NewDNSProviderCredentials(addrstr, "", "", "")
|
||||
provider, err := NewDNSProviderCredentials(server.ListenAddr(), "", "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Expected NewDNSProviderCredentials() to return no error but the error was -> %v", err)
|
||||
}
|
||||
@@ -239,29 +241,6 @@ func TestRFC2136ValidUpdatePacket(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func runLocalDNSTestServer(listenAddr string, tsig bool) (*dns.Server, string, error) {
|
||||
pc, err := net.ListenPacket("udp", listenAddr)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
server := &dns.Server{PacketConn: pc, ReadTimeout: time.Hour, WriteTimeout: time.Hour}
|
||||
if tsig {
|
||||
server.TsigSecret = map[string]string{rfc2136TestTsigKeyName: rfc2136TestTsigSecret}
|
||||
}
|
||||
|
||||
waitLock := sync.Mutex{}
|
||||
waitLock.Lock()
|
||||
server.NotifyStartedFunc = waitLock.Unlock
|
||||
|
||||
go func() {
|
||||
server.ActivateAndServe()
|
||||
pc.Close()
|
||||
}()
|
||||
|
||||
waitLock.Lock()
|
||||
return server, pc.LocalAddr().String(), nil
|
||||
}
|
||||
|
||||
func serverHandlerHello(w dns.ResponseWriter, req *dns.Msg) {
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(req)
|
||||
@@ -297,56 +276,3 @@ func serverHandlerReturnErr(w dns.ResponseWriter, req *dns.Msg) {
|
||||
m.SetRcode(req, dns.RcodeNotZone)
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
|
||||
type basicStatefulServer struct {
|
||||
txtRecords map[string][]string
|
||||
}
|
||||
|
||||
func (b *basicStatefulServer) serverHandlerPassBackRequest(w dns.ResponseWriter, req *dns.Msg) {
|
||||
if b.txtRecords == nil {
|
||||
b.txtRecords = make(map[string][]string)
|
||||
}
|
||||
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(req)
|
||||
defer w.WriteMsg(m)
|
||||
|
||||
if t := req.IsTsig(); t != nil {
|
||||
if w.TsigStatus() == nil {
|
||||
// Validated
|
||||
m.SetTsig(rfc2136TestZone, dns.HmacMD5, 300, time.Now().Unix())
|
||||
}
|
||||
}
|
||||
|
||||
if (req.Opcode != dns.OpcodeUpdate && req.Opcode != dns.OpcodeQuery) || req.Question[0].Qclass != dns.ClassINET {
|
||||
klog.Infof("skipping dns packet: %#v", req)
|
||||
//m.Rcode = dns.RcodeServerFailure
|
||||
return
|
||||
}
|
||||
|
||||
if req.Opcode == dns.OpcodeUpdate {
|
||||
for _, rr := range req.Ns {
|
||||
txt := rr.(*dns.TXT)
|
||||
if rr.Header().Class == dns.ClassNONE {
|
||||
klog.Infof("deleting val %q", txt.Hdr.Name)
|
||||
delete(b.txtRecords, txt.Hdr.Name)
|
||||
continue
|
||||
}
|
||||
klog.Infof("setting value %q: %v", txt.Hdr.Name, txt.Txt)
|
||||
b.txtRecords[txt.Hdr.Name] = txt.Txt
|
||||
}
|
||||
}
|
||||
|
||||
switch req.Question[0].Qtype {
|
||||
case dns.TypeSOA:
|
||||
// Return SOA to appease findZoneByFqdn()
|
||||
soaRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN SOA ns1.%s admin.%s 2016022801 28800 7200 2419200 1200", rfc2136TestZone, rfc2136TestTTL, rfc2136TestZone, rfc2136TestZone))
|
||||
m.Answer = []dns.RR{soaRR}
|
||||
case dns.TypeTXT:
|
||||
for _, rr := range b.txtRecords[req.Question[0].Name] {
|
||||
klog.Infof("returning %q", fmt.Sprintf("%s %d IN TXT %s", req.Question[0].Name, rfc2136TestTTL, rr))
|
||||
txtRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN TXT %s", req.Question[0].Name, rfc2136TestTTL, rr))
|
||||
m.Answer = append(m.Answer, txtRR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,10 @@ filegroup(
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//test/acme/dns/server:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"rfc2136.go",
|
||||
"server.go",
|
||||
],
|
||||
importpath = "github.com/jetstack/cert-manager/test/acme/dns/server",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/logs:go_default_library",
|
||||
"//vendor/github.com/go-logr/logr:go_default_library",
|
||||
"//vendor/github.com/miekg/dns:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
Copyright 2019 The Jetstack cert-manager contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package server implements an extremely basic DNS server that only responds
|
||||
// to a very limited subset of DNS requests.
|
||||
// It is suitable for use during testing RFC2136 updates and TXT record lookup.
|
||||
|
||||
package server
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
Copyright 2019 The Jetstack cert-manager contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
type rfc2136Handler struct {
|
||||
log logr.Logger
|
||||
|
||||
txtRecords map[string][]string
|
||||
zones []string
|
||||
tsigZone string
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// serveDNS implements github.com/miekg/dns.Handler
|
||||
func (b *rfc2136Handler) ServeDNS(w dns.ResponseWriter, req *dns.Msg) {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
log := b.log.WithName("serveDNS")
|
||||
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(req)
|
||||
defer w.WriteMsg(m)
|
||||
|
||||
var zone string
|
||||
if len(req.Question) > 0 {
|
||||
question := req.Question[0].Name
|
||||
log = log.WithValues("question", question, "opcode", dns.OpcodeToString[req.Opcode])
|
||||
zone = b.zoneForFQDN(question)
|
||||
if zone == "" {
|
||||
log.Info("failed to lookup zone for fqdn")
|
||||
m.Rcode = dns.RcodeServerFailure
|
||||
return
|
||||
}
|
||||
log = log.WithValues("zone", zone)
|
||||
}
|
||||
|
||||
if t := req.IsTsig(); t != nil {
|
||||
log.Info("TSIG requested on DNS request")
|
||||
if w.TsigStatus() == nil {
|
||||
log.Info("setting TSIG values on response")
|
||||
// Validated
|
||||
m.SetTsig(b.tsigZone, dns.HmacMD5, 300, time.Now().Unix())
|
||||
}
|
||||
}
|
||||
|
||||
// updates are currently accepted for *all* zones
|
||||
if req.Opcode == dns.OpcodeUpdate {
|
||||
for _, rr := range req.Ns {
|
||||
txt := rr.(*dns.TXT)
|
||||
log := log.WithValues("value", txt.Hdr.Name, "class", dns.ClassToString[rr.Header().Class], "txt", txt.Txt)
|
||||
if rr.Header().Class == dns.ClassNONE {
|
||||
log.Info("deleting txt record value due to NONE class")
|
||||
// TODO: can we only delete the named record here somehow?
|
||||
delete(b.txtRecords, txt.Hdr.Name)
|
||||
continue
|
||||
}
|
||||
log.Info("setting TXT record value")
|
||||
b.txtRecords[txt.Hdr.Name] = txt.Txt
|
||||
}
|
||||
}
|
||||
|
||||
switch req.Question[0].Qtype {
|
||||
case dns.TypeSOA:
|
||||
// Return SOA to appease findZoneByFqdn()
|
||||
soaRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN SOA ns1.%s admin.%s 2016022801 28800 7200 2419200 1200", zone, defaultTTL, zone, zone))
|
||||
m.Answer = []dns.RR{soaRR}
|
||||
case dns.TypeTXT:
|
||||
for _, rr := range b.txtRecords[req.Question[0].Name] {
|
||||
txtRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN TXT %s", req.Question[0].Name, defaultTTL, rr))
|
||||
m.Answer = append(m.Answer, txtRR)
|
||||
}
|
||||
}
|
||||
|
||||
for _, rr := range m.Answer {
|
||||
log.Info("responding", "response", rr.String())
|
||||
}
|
||||
}
|
||||
|
||||
func (b *rfc2136Handler) zoneForFQDN(s string) string {
|
||||
for _, z := range b.zones {
|
||||
if dns.IsSubDomain(z, s) {
|
||||
return z
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
Copyright 2019 The Jetstack cert-manager contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
|
||||
logf "github.com/jetstack/cert-manager/pkg/logs"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTTL = 60
|
||||
)
|
||||
|
||||
type BasicServer struct {
|
||||
// Zones is a list of DNS zones that this server should accept responses
|
||||
// for.
|
||||
Zones []string
|
||||
|
||||
// Handler is an optional
|
||||
Handler dns.Handler
|
||||
|
||||
// TSIG configuration options
|
||||
// EnableTSIG enables TSIG support for the DNS server
|
||||
// If true, both TSIGKeyName and TSIGKeySecret must be provided.
|
||||
EnableTSIG bool
|
||||
// TSIGKeyName to be used in responses when TSIG is enabled
|
||||
TSIGKeyName string
|
||||
// TSIGKeySecret to be used in responses when TSIG is enabled
|
||||
TSIGKeySecret string
|
||||
// TSIGZone is the DNS zone that should be used in TSIG responses
|
||||
TSIGZone string
|
||||
|
||||
ctx context.Context
|
||||
listenAddr string
|
||||
server *dns.Server
|
||||
}
|
||||
|
||||
// Run starts the test DNS server, binding to a random port on 127.0.0.1
|
||||
func (b *BasicServer) Run(ctx context.Context) error {
|
||||
return b.RunWithAddress(ctx, "127.0.0.1:0")
|
||||
}
|
||||
|
||||
// RunWithAddress starts the test DNS server using the specified listen address.
|
||||
func (b *BasicServer) RunWithAddress(ctx context.Context, listenAddr string) error {
|
||||
log := logf.FromContext(ctx, "dnsBasicServer")
|
||||
|
||||
if listenAddr == "" {
|
||||
return fmt.Errorf("listen address must be provided")
|
||||
}
|
||||
|
||||
pc, err := net.ListenPacket("udp", listenAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.listenAddr = pc.LocalAddr().String()
|
||||
log = log.WithValues("address", b.listenAddr)
|
||||
log.Info("listening on UDP port")
|
||||
|
||||
// update the ctx with the new logger
|
||||
ctx = logf.NewContext(ctx, log)
|
||||
|
||||
b.server = &dns.Server{PacketConn: pc, ReadTimeout: time.Hour, WriteTimeout: time.Hour}
|
||||
if b.EnableTSIG {
|
||||
log.Info("enabling TSIG support")
|
||||
b.server.TsigSecret = map[string]string{b.TSIGKeyName: b.TSIGKeySecret}
|
||||
}
|
||||
|
||||
if b.Handler == nil {
|
||||
b.Handler = &rfc2136Handler{
|
||||
log: log,
|
||||
txtRecords: make(map[string][]string),
|
||||
zones: b.Zones,
|
||||
tsigZone: b.TSIGZone,
|
||||
}
|
||||
}
|
||||
b.server.Handler = b.Handler
|
||||
|
||||
// Start the DNS server in a separate goroutine and wait for it to start
|
||||
waitLock := sync.Mutex{}
|
||||
waitLock.Lock()
|
||||
b.server.NotifyStartedFunc = waitLock.Unlock
|
||||
go func() {
|
||||
log.Info("starting DNS server")
|
||||
b.server.ActivateAndServe()
|
||||
log.Info("DNS server exited")
|
||||
pc.Close()
|
||||
}()
|
||||
waitLock.Lock()
|
||||
defer waitLock.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BasicServer) ListenAddr() string {
|
||||
return b.listenAddr
|
||||
}
|
||||
|
||||
func (b *BasicServer) Shutdown() error {
|
||||
return b.server.Shutdown()
|
||||
}
|
||||
Reference in New Issue
Block a user