mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-10-05 15:26:57 +08:00
feat: retry dns query
This commit is contained in:
@@ -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"
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
|
@@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -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)
|
||||||
}
|
}
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user