Source File
dns_resolver.go
Belonging Package
google.golang.org/grpc/internal/resolver/dns
package dns
import (
grpclbstate
)
var EnableSRVLookups = false
var logger = grpclog.Component("dns")
func () {
resolver.Register(NewBuilder())
}
const (
defaultPort = "443"
defaultDNSSvrPort = "53"
txtAttribute = "grpc_config="
)
var (
errMissingAddr = errors.New("dns resolver: missing address")
errEndsWithColon = errors.New("dns resolver: missing port after port-separator colon")
)
var (
minDNSResRate = 30 * time.Second
)
var customAuthorityDialler = func( string) func( context.Context, , string) (net.Conn, error) {
return func( context.Context, , string) (net.Conn, error) {
var net.Dialer
return .DialContext(, , )
}
}
var customAuthorityResolver = func( string) (netResolver, error) {
, , := parseTarget(, defaultDNSSvrPort)
if != nil {
return nil,
}
:= net.JoinHostPort(, )
return &net.Resolver{
PreferGo: true,
Dial: customAuthorityDialler(),
}, nil
}
func () resolver.Builder {
return &dnsBuilder{}
}
type dnsBuilder struct{}
func ( *dnsBuilder) ( resolver.Target, resolver.ClientConn, resolver.BuildOptions) (resolver.Resolver, error) {
, , := parseTarget(.Endpoint, defaultPort)
if != nil {
return nil,
}
if , := formatIP(); {
:= []resolver.Address{{Addr: + ":" + }}
.UpdateState(resolver.State{Addresses: })
return deadResolver{}, nil
}
, := context.WithCancel(context.Background())
:= &dnsResolver{
host: ,
port: ,
ctx: ,
cancel: ,
cc: ,
rn: make(chan struct{}, 1),
disableServiceConfig: .DisableServiceConfig,
}
if .Authority == "" {
.resolver = defaultResolver
} else {
.resolver, = customAuthorityResolver(.Authority)
if != nil {
return nil,
}
}
.wg.Add(1)
go .watcher()
.ResolveNow(resolver.ResolveNowOptions{})
return , nil
}
func ( *dnsBuilder) () string {
return "dns"
}
type netResolver interface {
LookupHost(ctx context.Context, host string) (addrs []string, err error)
LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*net.SRV, err error)
LookupTXT(ctx context.Context, name string) (txts []string, err error)
}
type deadResolver struct{}
func (deadResolver) (resolver.ResolveNowOptions) {}
func (deadResolver) () {}
type dnsResolver struct {
host string
port string
resolver netResolver
ctx context.Context
cancel context.CancelFunc
func ( *dnsResolver) (resolver.ResolveNowOptions) {
select {
case .rn <- struct{}{}:
default:
}
}
func ( *dnsResolver) () {
.cancel()
.wg.Wait()
}
func ( *dnsResolver) () {
defer .wg.Done()
for {
select {
case <-.ctx.Done():
return
case <-.rn:
}
, := .lookup()
if != nil {
.cc.ReportError()
} else {
.cc.UpdateState(*)
}
:= time.NewTimer(minDNSResRate)
select {
case <-.C:
case <-.ctx.Done():
.Stop()
return
}
}
}
func ( *dnsResolver) () ([]resolver.Address, error) {
if !EnableSRVLookups {
return nil, nil
}
var []resolver.Address
, , := .resolver.LookupSRV(.ctx, "grpclb", "tcp", .host)
if != nil {
= handleDNSError(, "SRV") // may become nil
return nil,
}
for , := range {
, := .resolver.LookupHost(.ctx, .Target)
if != nil {
= handleDNSError(, "A") // may become nil
return nil
}
return
}
func ( error, string) error {
= filterError()
if != nil {
= fmt.Errorf("dns: %v record lookup error: %v", , )
logger.Info()
}
return
}
func ( *dnsResolver) () *serviceconfig.ParseResult {
, := .resolver.LookupTXT(.ctx, txtPrefix+.host)
if != nil {
if envconfig.TXTErrIgnore {
return nil
}
if = handleDNSError(, "TXT"); != nil {
return &serviceconfig.ParseResult{Err: }
}
return nil
}
var string
for , := range {
+=
}
if !strings.HasPrefix(, txtAttribute) {
return nil
}
:= canaryingSC(strings.TrimPrefix(, txtAttribute))
return .cc.ParseServiceConfig()
}
func ( *dnsResolver) () ([]resolver.Address, error) {
var []resolver.Address
, := .resolver.LookupHost(.ctx, .host)
if != nil {
= handleDNSError(, "A")
return nil,
}
for , := range {
, := formatIP()
if ! {
return nil, fmt.Errorf("dns: error parsing A record IP address %v", )
}
:= + ":" + .port
= append(, resolver.Address{Addr: })
}
return , nil
}
func ( *dnsResolver) () (*resolver.State, error) {
, := .lookupSRV()
, := .lookupHost()
if != nil && ( != nil || len() == 0) {
return nil,
}
:= resolver.State{Addresses: }
if len() > 0 {
= grpclbstate.Set(, &grpclbstate.State{BalancerAddresses: })
}
if !.disableServiceConfig {
.ServiceConfig = .lookupTXT()
}
return &, nil
}
func (, string) (, string, error) {
if == "" {
return "", "", errMissingAddr
}
return , , nil
}
if , , = net.SplitHostPort(); == nil {
return "", "", errEndsWithColon
= "localhost"
}
return , , nil
}
return , , nil
}
return "", "", fmt.Errorf("invalid target address %v, error info: %v", , )
}
type rawChoice struct {
ClientLanguage *[]string `json:"clientLanguage,omitempty"`
Percentage *int `json:"percentage,omitempty"`
ClientHostName *[]string `json:"clientHostName,omitempty"`
ServiceConfig *json.RawMessage `json:"serviceConfig,omitempty"`
}
func ( *[]string, string) bool {
if == nil {
return true
}
for , := range * {
if == {
return true
}
}
return false
}
func ( *int) bool {
if == nil {
return true
}
return grpcrand.Intn(100)+1 <= *
}
func ( string) string {
if == "" {
return ""
}
var []rawChoice
:= json.Unmarshal([]byte(), &)
if != nil {
logger.Warningf("dns: error parsing service config json: %v", )
return ""
}
, := os.Hostname()
if != nil {
logger.Warningf("dns: error getting client hostname: %v", )
return ""
}
var string
for , := range {
if !containsString(.ClientLanguage, golang) ||
!chosenByPercentage(.Percentage) ||
!containsString(.ClientHostName, ) ||
.ServiceConfig == nil {
continue
}
= string(*.ServiceConfig)
break
}
return
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |