feat: retry dns query

This commit is contained in:
fengcaiwen
2022-12-14 21:57:31 +08:00
parent dac083e7b3
commit a07b5cae2e
6 changed files with 95 additions and 122 deletions

View File

@@ -12,7 +12,7 @@ import (
) )
// systemd-resolve --status, systemd-resolve --flush-caches // systemd-resolve --status, systemd-resolve --flush-caches
func SetupDNS(config *miekgdns.ClientConfig) error { func SetupDNS(config *miekgdns.ClientConfig, _ []string) error {
tunName := os.Getenv("tunName") tunName := os.Getenv("tunName")
if len(tunName) == 0 { if len(tunName) == 0 {
tunName = "tun0" tunName = "tun0"

View File

@@ -2,75 +2,98 @@ package dns
import ( import (
"context" "context"
"fmt"
"strings" "strings"
"sync/atomic"
"time" "time"
miekgdns "github.com/miekg/dns" miekgdns "github.com/miekg/dns"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/util/cache" "k8s.io/apimachinery/pkg/util/cache"
"k8s.io/apimachinery/pkg/util/sets"
) )
type server struct { type server struct {
// todo using cache to speed up dns resolve process
dnsCache *cache.LRUExpireCache dnsCache *cache.LRUExpireCache
forwardDNS *miekgdns.ClientConfig forwardDNS *miekgdns.ClientConfig
c *miekgdns.Client
} }
func NewDNSServer(network, address string, forwardDNS *miekgdns.ClientConfig) error { func NewDNSServer(network, address string, forwardDNS *miekgdns.ClientConfig) error {
return miekgdns.ListenAndServe(address, network, &server{ return miekgdns.ListenAndServe(address, network, &server{
dnsCache: cache.NewLRUExpireCache(1000), dnsCache: cache.NewLRUExpireCache(1000),
forwardDNS: forwardDNS, forwardDNS: forwardDNS,
c: &miekgdns.Client{Net: "udp" /*, SingleInflight: true*/},
}) })
} }
// ServeDNS consider using a cache // ServeDNS consider using a cache
func (s *server) ServeDNS(w miekgdns.ResponseWriter, r *miekgdns.Msg) { func (s *server) ServeDNS(w miekgdns.ResponseWriter, r *miekgdns.Msg) {
//defer w.Close() if len(r.Question) == 0 {
ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*3)
defer cancelFunc()
for _, dnsAddr := range s.forwardDNS.Servers {
var msg = new(miekgdns.Msg)
*msg = *r
go func(r miekgdns.Msg, dnsAddr string) {
var q = r.Question[0]
var originName = q.Name
q.Name = fix(originName, s.forwardDNS.Search[0])
r.Question = []miekgdns.Question{q}
answer, err := miekgdns.Exchange(&r, dnsAddr+":53")
if err == nil && len(answer.Answer) != 0 {
if len(answer.Answer) != 0 {
answer.Answer[0].Header().Name = originName
}
if len(answer.Question) != 0 {
answer.Question[0].Name = originName
}
if ctx.Err() == nil {
defer cancelFunc()
err = w.WriteMsg(answer)
if err != nil {
log.Debugf(err.Error())
}
}
return
}
if err != nil {
log.Debugf(err.Error())
}
}(*msg, dnsAddr)
}
<-ctx.Done()
if ctx.Err() != context.Canceled {
r.Response = true r.Response = true
_ = w.WriteMsg(r) _ = w.WriteMsg(r)
return
}
get, b := s.dnsCache.Get(r.Question[0].Name)
if b {
r.Response = true
r.Answer = get.([]miekgdns.RR)
_ = w.WriteMsg(r)
return
}
ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*5)
defer cancelFunc()
var ok = &atomic.Value{}
ok.Store(false)
var q = r.Question[0]
var originName = q.Name
for _, dnsAddr := range s.forwardDNS.Servers {
for _, name := range fix(originName, s.forwardDNS.Search) {
go func(name, dnsAddr string) {
var msg = new(miekgdns.Msg)
*msg = *r
q.Name = name
r.Question = []miekgdns.Question{q}
answer, _, err := s.c.ExchangeContext(ctx, msg, fmt.Sprintf("%s:%s", dnsAddr, s.forwardDNS.Port))
if err == nil && len(answer.Answer) != 0 {
for i := 0; i < len(answer.Answer); i++ {
answer.Answer[i].Header().Name = originName
}
//answer.Answer[0].Header().Name = originName
if len(answer.Question) != 0 {
answer.Question[0].Name = originName
}
if ctx.Err() == nil {
defer cancelFunc()
ok.Store(true)
err = w.WriteMsg(answer)
if err != nil {
log.Debugf(err.Error())
}
}
return
}
if err != nil {
log.Debugf(err.Error())
}
}(name, dnsAddr)
}
}
<-ctx.Done()
if !ok.Load().(bool) {
r.Response = true
_ = w.WriteMsg(r)
} else {
s.dnsCache.Add(r.Question[0].Name, r.Answer, time.Second*1)
} }
} }
func fix(domain, suffix string) string { func fix(domain string, suffix []string) (result []string) {
namespace := strings.Split(suffix, ".")[0] result = []string{domain}
if sets.NewString(strings.Split(domain, ".")...).Has(namespace) { for _, s := range suffix {
domain = domain[0:strings.LastIndex(domain, namespace)] result = append(result, strings.TrimSuffix(domain, ".")+"."+s+".")
} }
return strings.TrimSuffix(domain, ".") + "." + suffix + "." return
} }

View File

@@ -2,7 +2,7 @@ package dns
import ( import (
"fmt" "fmt"
miekgdns "github.com/miekg/dns" log "github.com/sirupsen/logrus"
"io/fs" "io/fs"
"io/ioutil" "io/ioutil"
"os" "os"
@@ -11,6 +11,8 @@ import (
"strings" "strings"
"testing" "testing"
miekgdns "github.com/miekg/dns"
"github.com/wencaiwulue/kubevpn/pkg/util" "github.com/wencaiwulue/kubevpn/pkg/util"
) )
@@ -22,12 +24,7 @@ func TestSetupDnsServer(t *testing.T) {
Port: "53", Port: "53",
Ndots: 0, Ndots: 0,
} }
go func() { go func() { log.Fatal(NewDNSServer("udp", "127.0.0.1:"+strconv.Itoa(port), clientConfig)) }()
err := NewDNSServer("udp", "127.0.0.1:"+strconv.Itoa(port), clientConfig)
if err != nil {
t.FailNow()
}
}()
config := miekgdns.ClientConfig{ config := miekgdns.ClientConfig{
Servers: []string{"127.0.0.1"}, Servers: []string{"127.0.0.1"},
Search: clientConfig.Search, Search: clientConfig.Search,
@@ -73,68 +70,3 @@ func TestFull(t *testing.T) {
fmt.Println(p2.Question) fmt.Println(p2.Question)
} }
func TestName(t *testing.T) {
type name struct {
input string
output string
}
var data = []name{
{
input: "ry-server",
output: "ry-server.vke-system.svc.cluster.local",
},
{
input: "ry-server.",
output: "ry-server.vke-system.svc.cluster.local",
},
{
input: "ry-server.vke-system",
output: "ry-server.vke-system.svc.cluster.local",
}, {
input: "ry-server.vke-system.",
output: "ry-server.vke-system.svc.cluster.local",
},
{
input: "ry-server.vke-system.svc",
output: "ry-server.vke-system.svc.cluster.local",
},
{
input: "ry-server.vke-system.svc.",
output: "ry-server.vke-system.svc.cluster.local",
},
{
input: "ry-server.vke-system.svc.cluster",
output: "ry-server.vke-system.svc.cluster.local",
},
{
input: "mongodb-1.mongodb-headless",
output: "mongodb-1.mongodb-headless.vke-system.svc.cluster.local",
}, {
input: "mongodb-1.mongodb-headless.",
output: "mongodb-1.mongodb-headless.vke-system.svc.cluster.local",
},
{
input: "mongodb-1.mongodb-headless.vke-system",
output: "mongodb-1.mongodb-headless.vke-system.svc.cluster.local",
},
{
input: "mongodb-1.mongodb-headless.vke-system.",
output: "mongodb-1.mongodb-headless.vke-system.svc.cluster.local",
},
{
input: "mongodb-1.mongodb-headless.vke-system.svc",
output: "mongodb-1.mongodb-headless.vke-system.svc.cluster.local",
},
{
input: "mongodb-1.mongodb-headless.vke-system.svc.cluster",
output: "mongodb-1.mongodb-headless.vke-system.svc.cluster.local",
},
}
for _, datum := range data {
if o := fix(datum.input, "vke-system.svc.cluster.local"); o != datum.output {
t.Logf("output: %s, expected: %s", o, datum.output)
t.FailNow()
}
}
}

View File

@@ -32,15 +32,15 @@ var resolv = "/etc/resolv.conf"
// service.namespace.svc:port // service.namespace.svc:port
// service.namespace.svc.cluster:port // service.namespace.svc.cluster:port
// service.namespace.svc.cluster.local:port // service.namespace.svc.cluster.local:port
func SetupDNS(config *miekgdns.ClientConfig) error { func SetupDNS(config *miekgdns.ClientConfig, ns []string) error {
usingResolver(config) usingResolver(config, ns)
_ = exec.Command("killall", "mDNSResponderHelper").Run() _ = exec.Command("killall", "mDNSResponderHelper").Run()
_ = exec.Command("killall", "-HUP", "mDNSResponder").Run() _ = exec.Command("killall", "-HUP", "mDNSResponder").Run()
_ = exec.Command("dscacheutil", "-flushcache").Run() _ = exec.Command("dscacheutil", "-flushcache").Run()
return nil return nil
} }
func usingResolver(clientConfig *miekgdns.ClientConfig) { func usingResolver(clientConfig *miekgdns.ClientConfig, ns []string) {
var err error var err error
_ = os.RemoveAll(filepath.Join("/", "etc", "resolver")) _ = os.RemoveAll(filepath.Join("/", "etc", "resolver"))
if err = os.MkdirAll(filepath.Join("/", "etc", "resolver"), fs.ModePerm); err != nil { if err = os.MkdirAll(filepath.Join("/", "etc", "resolver"), fs.ModePerm); err != nil {
@@ -70,7 +70,7 @@ func usingResolver(clientConfig *miekgdns.ClientConfig) {
Ndots: clientConfig.Ndots, Ndots: clientConfig.Ndots,
Timeout: 1, Timeout: 1,
} }
for _, s := range strings.Split(clientConfig.Search[0], ".") { for _, s := range sets.NewString(strings.Split(clientConfig.Search[0], ".")...).Insert(ns...).List() {
filename = filepath.Join("/", "etc", "resolver", s) filename = filepath.Join("/", "etc", "resolver", s)
_ = ioutil.WriteFile(filename, []byte(toString(config)), 0644) _ = ioutil.WriteFile(filename, []byte(toString(config)), 0644)
} }

View File

@@ -17,7 +17,7 @@ import (
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
) )
func SetupDNS(config *miekgdns.ClientConfig) error { func SetupDNS(config *miekgdns.ClientConfig, _ []string) error {
getenv := os.Getenv("luid") getenv := os.Getenv("luid")
parseUint, err := strconv.ParseUint(getenv, 10, 64) parseUint, err := strconv.ParseUint(getenv, 10, 64)
if err != nil { if err != nil {

View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"net" "net"
"os" "os"
"strconv"
"strings" "strings"
"sync/atomic" "sync/atomic"
"time" "time"
@@ -289,6 +290,7 @@ func (c *ConnectOptions) detectConflictDevice() {
} }
func (c *ConnectOptions) setupDNS() { func (c *ConnectOptions) setupDNS() {
const port = 53
pod, err := c.GetRunningPodList() pod, err := c.GetRunningPodList()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@@ -297,7 +299,23 @@ func (c *ConnectOptions) setupDNS() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
if err = dns.SetupDNS(relovConf); err != nil { if relovConf.Port == "" {
relovConf.Port = strconv.Itoa(port)
}
ns := sets.NewString()
list, err := c.clientset.CoreV1().Namespaces().List(ctx, metav1.ListOptions{})
if err == nil {
for _, item := range list.Items {
ns.Insert(item.Name)
}
}
svc, err := c.clientset.CoreV1().Services(c.Namespace).List(ctx, metav1.ListOptions{})
if err == nil {
for _, item := range svc.Items {
ns.Insert(item.Name)
}
}
if err = dns.SetupDNS(relovConf, ns.List()); err != nil {
log.Fatal(err) log.Fatal(err)
} }
} }