diff --git a/pkg/dns/dns_linux.go b/pkg/dns/dns_linux.go index a94899c3..f7225b3b 100644 --- a/pkg/dns/dns_linux.go +++ b/pkg/dns/dns_linux.go @@ -12,7 +12,7 @@ import ( ) // systemd-resolve --status, systemd-resolve --flush-caches -func SetupDNS(config *miekgdns.ClientConfig) error { +func SetupDNS(config *miekgdns.ClientConfig, _ []string) error { tunName := os.Getenv("tunName") if len(tunName) == 0 { tunName = "tun0" diff --git a/pkg/dns/dns_server.go b/pkg/dns/dns_server.go index 4f61f8fe..f8cc5989 100644 --- a/pkg/dns/dns_server.go +++ b/pkg/dns/dns_server.go @@ -2,75 +2,98 @@ package dns import ( "context" + "fmt" "strings" + "sync/atomic" "time" miekgdns "github.com/miekg/dns" log "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/util/cache" - "k8s.io/apimachinery/pkg/util/sets" ) type server struct { - // todo using cache to speed up dns resolve process dnsCache *cache.LRUExpireCache forwardDNS *miekgdns.ClientConfig + c *miekgdns.Client } func NewDNSServer(network, address string, forwardDNS *miekgdns.ClientConfig) error { return miekgdns.ListenAndServe(address, network, &server{ dnsCache: cache.NewLRUExpireCache(1000), forwardDNS: forwardDNS, + c: &miekgdns.Client{Net: "udp" /*, SingleInflight: true*/}, }) } // ServeDNS consider using a cache func (s *server) ServeDNS(w miekgdns.ResponseWriter, r *miekgdns.Msg) { - //defer w.Close() - 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 { + if len(r.Question) == 0 { r.Response = true _ = 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 { - namespace := strings.Split(suffix, ".")[0] - if sets.NewString(strings.Split(domain, ".")...).Has(namespace) { - domain = domain[0:strings.LastIndex(domain, namespace)] +func fix(domain string, suffix []string) (result []string) { + result = []string{domain} + for _, s := range suffix { + result = append(result, strings.TrimSuffix(domain, ".")+"."+s+".") } - return strings.TrimSuffix(domain, ".") + "." + suffix + "." + return } diff --git a/pkg/dns/dns_server_test.go b/pkg/dns/dns_server_test.go index 9eca90ae..985d69dc 100644 --- a/pkg/dns/dns_server_test.go +++ b/pkg/dns/dns_server_test.go @@ -2,7 +2,7 @@ package dns import ( "fmt" - miekgdns "github.com/miekg/dns" + log "github.com/sirupsen/logrus" "io/fs" "io/ioutil" "os" @@ -11,6 +11,8 @@ import ( "strings" "testing" + miekgdns "github.com/miekg/dns" + "github.com/wencaiwulue/kubevpn/pkg/util" ) @@ -22,12 +24,7 @@ func TestSetupDnsServer(t *testing.T) { Port: "53", Ndots: 0, } - go func() { - err := NewDNSServer("udp", "127.0.0.1:"+strconv.Itoa(port), clientConfig) - if err != nil { - t.FailNow() - } - }() + go func() { log.Fatal(NewDNSServer("udp", "127.0.0.1:"+strconv.Itoa(port), clientConfig)) }() config := miekgdns.ClientConfig{ Servers: []string{"127.0.0.1"}, Search: clientConfig.Search, @@ -73,68 +70,3 @@ func TestFull(t *testing.T) { 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() - } - } -} diff --git a/pkg/dns/dns_unix.go b/pkg/dns/dns_unix.go index bb256245..38a18840 100644 --- a/pkg/dns/dns_unix.go +++ b/pkg/dns/dns_unix.go @@ -32,15 +32,15 @@ var resolv = "/etc/resolv.conf" // service.namespace.svc:port // service.namespace.svc.cluster:port // service.namespace.svc.cluster.local:port -func SetupDNS(config *miekgdns.ClientConfig) error { - usingResolver(config) +func SetupDNS(config *miekgdns.ClientConfig, ns []string) error { + usingResolver(config, ns) _ = exec.Command("killall", "mDNSResponderHelper").Run() _ = exec.Command("killall", "-HUP", "mDNSResponder").Run() _ = exec.Command("dscacheutil", "-flushcache").Run() return nil } -func usingResolver(clientConfig *miekgdns.ClientConfig) { +func usingResolver(clientConfig *miekgdns.ClientConfig, ns []string) { var err error _ = os.RemoveAll(filepath.Join("/", "etc", "resolver")) if err = os.MkdirAll(filepath.Join("/", "etc", "resolver"), fs.ModePerm); err != nil { @@ -70,7 +70,7 @@ func usingResolver(clientConfig *miekgdns.ClientConfig) { Ndots: clientConfig.Ndots, 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) _ = ioutil.WriteFile(filename, []byte(toString(config)), 0644) } diff --git a/pkg/dns/dns_windows.go b/pkg/dns/dns_windows.go index a94e8040..fed81420 100644 --- a/pkg/dns/dns_windows.go +++ b/pkg/dns/dns_windows.go @@ -17,7 +17,7 @@ import ( "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" ) -func SetupDNS(config *miekgdns.ClientConfig) error { +func SetupDNS(config *miekgdns.ClientConfig, _ []string) error { getenv := os.Getenv("luid") parseUint, err := strconv.ParseUint(getenv, 10, 64) if err != nil { diff --git a/pkg/handler/connect.go b/pkg/handler/connect.go index 2a3a0b9f..309fb844 100644 --- a/pkg/handler/connect.go +++ b/pkg/handler/connect.go @@ -5,6 +5,7 @@ import ( "fmt" "net" "os" + "strconv" "strings" "sync/atomic" "time" @@ -289,6 +290,7 @@ func (c *ConnectOptions) detectConflictDevice() { } func (c *ConnectOptions) setupDNS() { + const port = 53 pod, err := c.GetRunningPodList() if err != nil { log.Fatal(err) @@ -297,7 +299,23 @@ func (c *ConnectOptions) setupDNS() { if err != nil { 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) } }