github.com/outbrain/consul@v1.4.5/agent/dns.go (about) 1 package agent 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 "log" 7 "net" 8 "strings" 9 "sync/atomic" 10 "time" 11 12 "regexp" 13 14 metrics "github.com/armon/go-metrics" 15 radix "github.com/armon/go-radix" 16 "github.com/coredns/coredns/plugin/pkg/dnsutil" 17 cachetype "github.com/hashicorp/consul/agent/cache-types" 18 "github.com/hashicorp/consul/agent/config" 19 "github.com/hashicorp/consul/agent/consul" 20 "github.com/hashicorp/consul/agent/structs" 21 "github.com/hashicorp/consul/api" 22 "github.com/hashicorp/consul/lib" 23 "github.com/miekg/dns" 24 ) 25 26 const ( 27 // UDP can fit ~25 A records in a 512B response, and ~14 AAAA 28 // records. Limit further to prevent unintentional configuration 29 // abuse that would have a negative effect on application response 30 // times. 31 maxUDPAnswerLimit = 8 32 maxRecurseRecords = 5 33 maxRecursionLevelDefault = 3 34 35 // Increment a counter when requests staler than this are served 36 staleCounterThreshold = 5 * time.Second 37 38 defaultMaxUDPSize = 512 39 40 MaxDNSLabelLength = 63 41 ) 42 43 var InvalidDnsRe = regexp.MustCompile(`[^A-Za-z0-9\\-]+`) 44 45 type dnsSOAConfig struct { 46 Refresh uint32 // 3600 by default 47 Retry uint32 // 600 48 Expire uint32 // 86400 49 Minttl uint32 // 0, 50 } 51 52 type dnsConfig struct { 53 AllowStale bool 54 Datacenter string 55 EnableTruncate bool 56 MaxStale time.Duration 57 UseCache bool 58 CacheMaxAge time.Duration 59 NodeName string 60 NodeTTL time.Duration 61 OnlyPassing bool 62 RecursorTimeout time.Duration 63 SegmentName string 64 ServiceTTL map[string]time.Duration 65 UDPAnswerLimit int 66 ARecordLimit int 67 NodeMetaTXT bool 68 dnsSOAConfig dnsSOAConfig 69 } 70 71 // DNSServer is used to wrap an Agent and expose various 72 // service discovery endpoints using a DNS interface. 73 type DNSServer struct { 74 *dns.Server 75 agent *Agent 76 config *dnsConfig 77 domain string 78 recursors []string 79 logger *log.Logger 80 // Those are handling prefix lookups 81 ttlRadix *radix.Tree 82 ttlStrict map[string]time.Duration 83 84 // disableCompression is the config.DisableCompression flag that can 85 // be safely changed at runtime. It always contains a bool and is 86 // initialized with the value from config.DisableCompression. 87 disableCompression atomic.Value 88 } 89 90 func NewDNSServer(a *Agent) (*DNSServer, error) { 91 var recursors []string 92 for _, r := range a.config.DNSRecursors { 93 ra, err := recursorAddr(r) 94 if err != nil { 95 return nil, fmt.Errorf("Invalid recursor address: %v", err) 96 } 97 recursors = append(recursors, ra) 98 } 99 100 // Make sure domain is FQDN, make it case insensitive for ServeMux 101 domain := dns.Fqdn(strings.ToLower(a.config.DNSDomain)) 102 103 dnscfg := GetDNSConfig(a.config) 104 srv := &DNSServer{ 105 agent: a, 106 config: dnscfg, 107 domain: domain, 108 logger: a.logger, 109 recursors: recursors, 110 ttlRadix: radix.New(), 111 ttlStrict: make(map[string]time.Duration), 112 } 113 if dnscfg.ServiceTTL != nil { 114 for key, ttl := range dnscfg.ServiceTTL { 115 // All suffix with '*' are put in radix 116 // This include '*' that will match anything 117 if strings.HasSuffix(key, "*") { 118 srv.ttlRadix.Insert(key[:len(key)-1], ttl) 119 } else { 120 srv.ttlStrict[key] = ttl 121 } 122 } 123 } 124 125 srv.disableCompression.Store(a.config.DNSDisableCompression) 126 127 return srv, nil 128 } 129 130 // GetDNSConfig takes global config and creates the config used by DNS server 131 func GetDNSConfig(conf *config.RuntimeConfig) *dnsConfig { 132 return &dnsConfig{ 133 AllowStale: conf.DNSAllowStale, 134 ARecordLimit: conf.DNSARecordLimit, 135 Datacenter: conf.Datacenter, 136 EnableTruncate: conf.DNSEnableTruncate, 137 MaxStale: conf.DNSMaxStale, 138 NodeName: conf.NodeName, 139 NodeTTL: conf.DNSNodeTTL, 140 OnlyPassing: conf.DNSOnlyPassing, 141 RecursorTimeout: conf.DNSRecursorTimeout, 142 SegmentName: conf.SegmentName, 143 ServiceTTL: conf.DNSServiceTTL, 144 UDPAnswerLimit: conf.DNSUDPAnswerLimit, 145 NodeMetaTXT: conf.DNSNodeMetaTXT, 146 UseCache: conf.DNSUseCache, 147 CacheMaxAge: conf.DNSCacheMaxAge, 148 dnsSOAConfig: dnsSOAConfig{ 149 Expire: conf.DNSSOA.Expire, 150 Minttl: conf.DNSSOA.Minttl, 151 Refresh: conf.DNSSOA.Refresh, 152 Retry: conf.DNSSOA.Retry, 153 }, 154 } 155 } 156 157 // GetTTLForService Find the TTL for a given service. 158 // return ttl, true if found, 0, false otherwise 159 func (d *DNSServer) GetTTLForService(service string) (time.Duration, bool) { 160 if d.config.ServiceTTL != nil { 161 ttl, ok := d.ttlStrict[service] 162 if ok { 163 return ttl, true 164 } 165 _, ttlRaw, ok := d.ttlRadix.LongestPrefix(service) 166 if ok { 167 return ttlRaw.(time.Duration), true 168 } 169 } 170 return time.Duration(0), false 171 } 172 173 func (d *DNSServer) ListenAndServe(network, addr string, notif func()) error { 174 mux := dns.NewServeMux() 175 mux.HandleFunc("arpa.", d.handlePtr) 176 mux.HandleFunc(d.domain, d.handleQuery) 177 if len(d.recursors) > 0 { 178 mux.HandleFunc(".", d.handleRecurse) 179 } 180 181 d.Server = &dns.Server{ 182 Addr: addr, 183 Net: network, 184 Handler: mux, 185 NotifyStartedFunc: notif, 186 } 187 if network == "udp" { 188 d.UDPSize = 65535 189 } 190 return d.Server.ListenAndServe() 191 } 192 193 // setEDNS is used to set the responses EDNS size headers and 194 // possibly the ECS headers as well if they were present in the 195 // original request 196 func setEDNS(request *dns.Msg, response *dns.Msg, ecsGlobal bool) { 197 // Enable EDNS if enabled 198 if edns := request.IsEdns0(); edns != nil { 199 // cannot just use the SetEdns0 function as we need to embed 200 // the ECS option as well 201 ednsResp := new(dns.OPT) 202 ednsResp.Hdr.Name = "." 203 ednsResp.Hdr.Rrtype = dns.TypeOPT 204 ednsResp.SetUDPSize(edns.UDPSize()) 205 206 // Setup the ECS option if present 207 if subnet := ednsSubnetForRequest(request); subnet != nil { 208 subOp := new(dns.EDNS0_SUBNET) 209 subOp.Code = dns.EDNS0SUBNET 210 subOp.Family = subnet.Family 211 subOp.Address = subnet.Address 212 subOp.SourceNetmask = subnet.SourceNetmask 213 if c := response.Rcode; ecsGlobal || c == dns.RcodeNameError || c == dns.RcodeServerFailure || c == dns.RcodeRefused || c == dns.RcodeNotImplemented { 214 // reply is globally valid and should be cached accordingly 215 subOp.SourceScope = 0 216 } else { 217 // reply is only valid for the subnet it was queried with 218 subOp.SourceScope = subnet.SourceNetmask 219 } 220 ednsResp.Option = append(ednsResp.Option, subOp) 221 } 222 223 response.Extra = append(response.Extra, ednsResp) 224 } 225 } 226 227 // recursorAddr is used to add a port to the recursor if omitted. 228 func recursorAddr(recursor string) (string, error) { 229 // Add the port if none 230 START: 231 _, _, err := net.SplitHostPort(recursor) 232 if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" { 233 recursor = fmt.Sprintf("%s:%d", recursor, 53) 234 goto START 235 } 236 if err != nil { 237 return "", err 238 } 239 240 // Get the address 241 addr, err := net.ResolveTCPAddr("tcp", recursor) 242 if err != nil { 243 return "", err 244 } 245 246 // Return string 247 return addr.String(), nil 248 } 249 250 // handlePtr is used to handle "reverse" DNS queries 251 func (d *DNSServer) handlePtr(resp dns.ResponseWriter, req *dns.Msg) { 252 q := req.Question[0] 253 defer func(s time.Time) { 254 metrics.MeasureSinceWithLabels([]string{"dns", "ptr_query"}, s, 255 []metrics.Label{{Name: "node", Value: d.agent.config.NodeName}}) 256 d.logger.Printf("[DEBUG] dns: request for %v (%v) from client %s (%s)", 257 q, time.Since(s), resp.RemoteAddr().String(), 258 resp.RemoteAddr().Network()) 259 }(time.Now()) 260 261 // Setup the message response 262 m := new(dns.Msg) 263 m.SetReply(req) 264 m.Compress = !d.disableCompression.Load().(bool) 265 m.Authoritative = true 266 m.RecursionAvailable = (len(d.recursors) > 0) 267 268 // Only add the SOA if requested 269 if req.Question[0].Qtype == dns.TypeSOA { 270 d.addSOA(m) 271 } 272 273 datacenter := d.agent.config.Datacenter 274 275 // Get the QName without the domain suffix 276 qName := strings.ToLower(dns.Fqdn(req.Question[0].Name)) 277 278 args := structs.DCSpecificRequest{ 279 Datacenter: datacenter, 280 QueryOptions: structs.QueryOptions{ 281 Token: d.agent.tokens.UserToken(), 282 AllowStale: d.config.AllowStale, 283 }, 284 } 285 var out structs.IndexedNodes 286 287 // TODO: Replace ListNodes with an internal RPC that can do the filter 288 // server side to avoid transferring the entire node list. 289 if err := d.agent.RPC("Catalog.ListNodes", &args, &out); err == nil { 290 for _, n := range out.Nodes { 291 arpa, _ := dns.ReverseAddr(n.Address) 292 if arpa == qName { 293 ptr := &dns.PTR{ 294 Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: 0}, 295 Ptr: fmt.Sprintf("%s.node.%s.%s", n.Node, datacenter, d.domain), 296 } 297 m.Answer = append(m.Answer, ptr) 298 break 299 } 300 } 301 } 302 303 // only look into the services if we didn't find a node 304 if len(m.Answer) == 0 { 305 // lookup the service address 306 serviceAddress := dnsutil.ExtractAddressFromReverse(qName) 307 sargs := structs.ServiceSpecificRequest{ 308 Datacenter: datacenter, 309 QueryOptions: structs.QueryOptions{ 310 Token: d.agent.tokens.UserToken(), 311 AllowStale: d.config.AllowStale, 312 }, 313 ServiceAddress: serviceAddress, 314 } 315 316 var sout structs.IndexedServiceNodes 317 if err := d.agent.RPC("Catalog.ServiceNodes", &sargs, &sout); err == nil { 318 for _, n := range sout.ServiceNodes { 319 if n.ServiceAddress == serviceAddress { 320 ptr := &dns.PTR{ 321 Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: 0}, 322 Ptr: fmt.Sprintf("%s.service.%s", n.ServiceName, d.domain), 323 } 324 m.Answer = append(m.Answer, ptr) 325 break 326 } 327 } 328 } 329 } 330 331 // nothing found locally, recurse 332 if len(m.Answer) == 0 { 333 d.handleRecurse(resp, req) 334 return 335 } 336 337 // ptr record responses are globally valid 338 setEDNS(req, m, true) 339 340 // Write out the complete response 341 if err := resp.WriteMsg(m); err != nil { 342 d.logger.Printf("[WARN] dns: failed to respond: %v", err) 343 } 344 } 345 346 // handleQuery is used to handle DNS queries in the configured domain 347 func (d *DNSServer) handleQuery(resp dns.ResponseWriter, req *dns.Msg) { 348 q := req.Question[0] 349 defer func(s time.Time) { 350 metrics.MeasureSinceWithLabels([]string{"dns", "domain_query"}, s, 351 []metrics.Label{{Name: "node", Value: d.agent.config.NodeName}}) 352 d.logger.Printf("[DEBUG] dns: request for name %v type %v class %v (took %v) from client %s (%s)", 353 q.Name, dns.Type(q.Qtype), dns.Class(q.Qclass), time.Since(s), resp.RemoteAddr().String(), 354 resp.RemoteAddr().Network()) 355 }(time.Now()) 356 357 // Switch to TCP if the client is 358 network := "udp" 359 if _, ok := resp.RemoteAddr().(*net.TCPAddr); ok { 360 network = "tcp" 361 } 362 363 // Setup the message response 364 m := new(dns.Msg) 365 m.SetReply(req) 366 m.Compress = !d.disableCompression.Load().(bool) 367 m.Authoritative = true 368 m.RecursionAvailable = (len(d.recursors) > 0) 369 370 ecsGlobal := true 371 372 switch req.Question[0].Qtype { 373 case dns.TypeSOA: 374 ns, glue := d.nameservers(req.IsEdns0() != nil, maxRecursionLevelDefault) 375 m.Answer = append(m.Answer, d.soa()) 376 m.Ns = append(m.Ns, ns...) 377 m.Extra = append(m.Extra, glue...) 378 m.SetRcode(req, dns.RcodeSuccess) 379 380 case dns.TypeNS: 381 ns, glue := d.nameservers(req.IsEdns0() != nil, maxRecursionLevelDefault) 382 m.Answer = ns 383 m.Extra = glue 384 m.SetRcode(req, dns.RcodeSuccess) 385 386 case dns.TypeAXFR: 387 m.SetRcode(req, dns.RcodeNotImplemented) 388 389 default: 390 ecsGlobal = d.dispatch(network, resp.RemoteAddr(), req, m) 391 } 392 393 setEDNS(req, m, ecsGlobal) 394 395 // Write out the complete response 396 if err := resp.WriteMsg(m); err != nil { 397 d.logger.Printf("[WARN] dns: failed to respond: %v", err) 398 } 399 } 400 401 func (d *DNSServer) soa() *dns.SOA { 402 return &dns.SOA{ 403 Hdr: dns.RR_Header{ 404 Name: d.domain, 405 Rrtype: dns.TypeSOA, 406 Class: dns.ClassINET, 407 // Has to be consistent with MinTTL to avoid invalidation 408 Ttl: d.config.dnsSOAConfig.Minttl, 409 }, 410 Ns: "ns." + d.domain, 411 Serial: uint32(time.Now().Unix()), 412 Mbox: "hostmaster." + d.domain, 413 Refresh: d.config.dnsSOAConfig.Refresh, 414 Retry: d.config.dnsSOAConfig.Retry, 415 Expire: d.config.dnsSOAConfig.Expire, 416 Minttl: d.config.dnsSOAConfig.Minttl, 417 } 418 } 419 420 // addSOA is used to add an SOA record to a message for the given domain 421 func (d *DNSServer) addSOA(msg *dns.Msg) { 422 msg.Ns = append(msg.Ns, d.soa()) 423 } 424 425 // nameservers returns the names and ip addresses of up to three random servers 426 // in the current cluster which serve as authoritative name servers for zone. 427 func (d *DNSServer) nameservers(edns bool, maxRecursionLevel int) (ns []dns.RR, extra []dns.RR) { 428 out, err := d.lookupServiceNodes(d.agent.config.Datacenter, structs.ConsulServiceName, "", false, maxRecursionLevel) 429 if err != nil { 430 d.logger.Printf("[WARN] dns: Unable to get list of servers: %s", err) 431 return nil, nil 432 } 433 434 if len(out.Nodes) == 0 { 435 d.logger.Printf("[WARN] dns: no servers found") 436 return 437 } 438 439 // shuffle the nodes to randomize the output 440 out.Nodes.Shuffle() 441 442 for _, o := range out.Nodes { 443 name, addr, dc := o.Node.Node, o.Node.Address, o.Node.Datacenter 444 445 if InvalidDnsRe.MatchString(name) { 446 d.logger.Printf("[WARN] dns: Skipping invalid node %q for NS records", name) 447 continue 448 } 449 450 fqdn := name + ".node." + dc + "." + d.domain 451 fqdn = dns.Fqdn(strings.ToLower(fqdn)) 452 453 // NS record 454 nsrr := &dns.NS{ 455 Hdr: dns.RR_Header{ 456 Name: d.domain, 457 Rrtype: dns.TypeNS, 458 Class: dns.ClassINET, 459 Ttl: uint32(d.config.NodeTTL / time.Second), 460 }, 461 Ns: fqdn, 462 } 463 ns = append(ns, nsrr) 464 465 glue, meta := d.formatNodeRecord(nil, addr, fqdn, dns.TypeANY, d.config.NodeTTL, edns, maxRecursionLevel, d.config.NodeMetaTXT) 466 extra = append(extra, glue...) 467 if meta != nil && d.config.NodeMetaTXT { 468 extra = append(extra, meta...) 469 } 470 471 // don't provide more than 3 servers 472 if len(ns) >= 3 { 473 return 474 } 475 } 476 477 return 478 } 479 480 // dispatch is used to parse a request and invoke the correct handler 481 func (d *DNSServer) dispatch(network string, remoteAddr net.Addr, req, resp *dns.Msg) (ecsGlobal bool) { 482 return d.doDispatch(network, remoteAddr, req, resp, maxRecursionLevelDefault) 483 } 484 485 // doDispatch is used to parse a request and invoke the correct handler. 486 // parameter maxRecursionLevel will handle whether recursive call can be performed 487 func (d *DNSServer) doDispatch(network string, remoteAddr net.Addr, req, resp *dns.Msg, maxRecursionLevel int) (ecsGlobal bool) { 488 ecsGlobal = true 489 // By default the query is in the default datacenter 490 datacenter := d.agent.config.Datacenter 491 492 // Get the QName without the domain suffix 493 qName := strings.ToLower(dns.Fqdn(req.Question[0].Name)) 494 qName = strings.TrimSuffix(qName, d.domain) 495 496 // Split into the label parts 497 labels := dns.SplitDomainName(qName) 498 499 // Provide a flag for remembering whether the datacenter name was parsed already. 500 var dcParsed bool 501 502 // The last label is either "node", "service", "query", "_<protocol>", or a datacenter name 503 PARSE: 504 n := len(labels) 505 if n == 0 { 506 goto INVALID 507 } 508 509 // If this is a SRV query the "service" label is optional, we add it back to use the 510 // existing code-path. 511 if req.Question[0].Qtype == dns.TypeSRV && strings.HasPrefix(labels[n-1], "_") { 512 labels = append(labels, "service") 513 n = n + 1 514 } 515 516 switch kind := labels[n-1]; kind { 517 case "service": 518 if n == 1 { 519 goto INVALID 520 } 521 522 // Support RFC 2782 style syntax 523 if n == 3 && strings.HasPrefix(labels[n-2], "_") && strings.HasPrefix(labels[n-3], "_") { 524 525 // Grab the tag since we make nuke it if it's tcp 526 tag := labels[n-2][1:] 527 528 // Treat _name._tcp.service.consul as a default, no need to filter on that tag 529 if tag == "tcp" { 530 tag = "" 531 } 532 533 // _name._tag.service.consul 534 d.serviceLookup(network, datacenter, labels[n-3][1:], tag, false, req, resp, maxRecursionLevel) 535 536 // Consul 0.3 and prior format for SRV queries 537 } else { 538 539 // Support "." in the label, re-join all the parts 540 tag := "" 541 if n >= 3 { 542 tag = strings.Join(labels[:n-2], ".") 543 } 544 545 // tag[.tag].name.service.consul 546 d.serviceLookup(network, datacenter, labels[n-2], tag, false, req, resp, maxRecursionLevel) 547 } 548 549 case "connect": 550 if n == 1 { 551 goto INVALID 552 } 553 554 // name.connect.consul 555 d.serviceLookup(network, datacenter, labels[n-2], "", true, req, resp, maxRecursionLevel) 556 557 case "node": 558 if n == 1 { 559 goto INVALID 560 } 561 562 // Allow a "." in the node name, just join all the parts 563 node := strings.Join(labels[:n-1], ".") 564 d.nodeLookup(network, datacenter, node, req, resp, maxRecursionLevel) 565 566 case "query": 567 if n == 1 { 568 goto INVALID 569 } 570 571 // Allow a "." in the query name, just join all the parts. 572 query := strings.Join(labels[:n-1], ".") 573 ecsGlobal = false 574 d.preparedQueryLookup(network, datacenter, query, remoteAddr, req, resp, maxRecursionLevel) 575 576 case "addr": 577 if n != 2 { 578 goto INVALID 579 } 580 581 switch len(labels[0]) / 2 { 582 // IPv4 583 case 4: 584 ip, err := hex.DecodeString(labels[0]) 585 if err != nil { 586 goto INVALID 587 } 588 589 resp.Answer = append(resp.Answer, &dns.A{ 590 Hdr: dns.RR_Header{ 591 Name: qName + d.domain, 592 Rrtype: dns.TypeA, 593 Class: dns.ClassINET, 594 Ttl: uint32(d.config.NodeTTL / time.Second), 595 }, 596 A: ip, 597 }) 598 // IPv6 599 case 16: 600 ip, err := hex.DecodeString(labels[0]) 601 if err != nil { 602 goto INVALID 603 } 604 605 resp.Answer = append(resp.Answer, &dns.AAAA{ 606 Hdr: dns.RR_Header{ 607 Name: qName + d.domain, 608 Rrtype: dns.TypeAAAA, 609 Class: dns.ClassINET, 610 Ttl: uint32(d.config.NodeTTL / time.Second), 611 }, 612 AAAA: ip, 613 }) 614 } 615 616 default: 617 // https://github.com/hashicorp/consul/issues/3200 618 // 619 // Since datacenter names cannot contain dots we can only allow one 620 // label between the query type and the domain to be the datacenter name. 621 // Since the datacenter name is optional and the parser strips off labels at the end until it finds a suitable 622 // query type label we return NXDOMAIN when we encounter another label 623 // which could be the datacenter name. 624 // 625 // If '.consul' is the domain then 626 // * foo.service.dc.consul is OK 627 // * foo.service.dc.stuff.consul is not OK 628 if dcParsed { 629 goto INVALID 630 } 631 dcParsed = true 632 633 // Store the DC, and re-parse 634 datacenter = labels[n-1] 635 labels = labels[:n-1] 636 goto PARSE 637 } 638 return 639 INVALID: 640 d.logger.Printf("[WARN] dns: QName invalid: %s", qName) 641 d.addSOA(resp) 642 resp.SetRcode(req, dns.RcodeNameError) 643 return 644 } 645 646 // nodeLookup is used to handle a node query 647 func (d *DNSServer) nodeLookup(network, datacenter, node string, req, resp *dns.Msg, maxRecursionLevel int) { 648 // Only handle ANY, A, AAAA, and TXT type requests 649 qType := req.Question[0].Qtype 650 if qType != dns.TypeANY && qType != dns.TypeA && qType != dns.TypeAAAA && qType != dns.TypeTXT { 651 return 652 } 653 654 // Make an RPC request 655 args := &structs.NodeSpecificRequest{ 656 Datacenter: datacenter, 657 Node: node, 658 QueryOptions: structs.QueryOptions{ 659 Token: d.agent.tokens.UserToken(), 660 AllowStale: d.config.AllowStale, 661 }, 662 } 663 out, err := d.lookupNode(args) 664 if err != nil { 665 d.logger.Printf("[ERR] dns: rpc error: %v", err) 666 resp.SetRcode(req, dns.RcodeServerFailure) 667 return 668 } 669 670 // If we have no address, return not found! 671 if out.NodeServices == nil { 672 d.addSOA(resp) 673 resp.SetRcode(req, dns.RcodeNameError) 674 return 675 } 676 677 generateMeta := false 678 metaInAnswer := false 679 if qType == dns.TypeANY || qType == dns.TypeTXT { 680 generateMeta = true 681 metaInAnswer = true 682 } else if d.config.NodeMetaTXT { 683 generateMeta = true 684 } 685 686 // Add the node record 687 n := out.NodeServices.Node 688 edns := req.IsEdns0() != nil 689 addr := d.agent.TranslateAddress(datacenter, n.Address, n.TaggedAddresses) 690 records, meta := d.formatNodeRecord(out.NodeServices.Node, addr, req.Question[0].Name, qType, d.config.NodeTTL, edns, maxRecursionLevel, generateMeta) 691 if records != nil { 692 resp.Answer = append(resp.Answer, records...) 693 } 694 if meta != nil && metaInAnswer && generateMeta { 695 resp.Answer = append(resp.Answer, meta...) 696 } else if meta != nil && generateMeta { 697 resp.Extra = append(resp.Extra, meta...) 698 } 699 } 700 701 func (d *DNSServer) lookupNode(args *structs.NodeSpecificRequest) (*structs.IndexedNodeServices, error) { 702 var out structs.IndexedNodeServices 703 704 useCache := d.config.UseCache 705 RPC: 706 if useCache { 707 raw, _, err := d.agent.cache.Get(cachetype.NodeServicesName, args) 708 if err != nil { 709 return nil, err 710 } 711 reply, ok := raw.(*structs.IndexedNodeServices) 712 if !ok { 713 // This should never happen, but we want to protect against panics 714 return nil, fmt.Errorf("internal error: response type not correct") 715 } 716 out = *reply 717 } else { 718 if err := d.agent.RPC("Catalog.NodeServices", &args, &out); err != nil { 719 return nil, err 720 } 721 } 722 723 // Verify that request is not too stale, redo the request 724 if args.AllowStale { 725 if out.LastContact > d.config.MaxStale { 726 args.AllowStale = false 727 useCache = false 728 d.logger.Printf("[WARN] dns: Query results too stale, re-requesting") 729 goto RPC 730 } else if out.LastContact > staleCounterThreshold { 731 metrics.IncrCounter([]string{"dns", "stale_queries"}, 1) 732 } 733 } 734 735 return &out, nil 736 } 737 738 // encodeKVasRFC1464 encodes a key-value pair according to RFC1464 739 func encodeKVasRFC1464(key, value string) (txt string) { 740 // For details on these replacements c.f. https://www.ietf.org/rfc/rfc1464.txt 741 key = strings.Replace(key, "`", "``", -1) 742 key = strings.Replace(key, "=", "`=", -1) 743 744 // Backquote the leading spaces 745 leadingSpacesRE := regexp.MustCompile("^ +") 746 numLeadingSpaces := len(leadingSpacesRE.FindString(key)) 747 key = leadingSpacesRE.ReplaceAllString(key, strings.Repeat("` ", numLeadingSpaces)) 748 749 // Backquote the trailing spaces 750 trailingSpacesRE := regexp.MustCompile(" +$") 751 numTrailingSpaces := len(trailingSpacesRE.FindString(key)) 752 key = trailingSpacesRE.ReplaceAllString(key, strings.Repeat("` ", numTrailingSpaces)) 753 754 value = strings.Replace(value, "`", "``", -1) 755 756 return key + "=" + value 757 } 758 759 // formatNodeRecord takes a Node and returns the RRs associated with that node 760 // 761 // The return value is two slices. The first slice is the main answer slice (containing the A, AAAA, CNAME) RRs for the node 762 // and the second slice contains any TXT RRs created from the node metadata. It is up to the caller to determine where the 763 // generated RRs should go and if they should be used at all. 764 func (d *DNSServer) formatNodeRecord(node *structs.Node, addr, qName string, qType uint16, ttl time.Duration, edns bool, maxRecursionLevel int, generateMeta bool) (records, meta []dns.RR) { 765 // Parse the IP 766 ip := net.ParseIP(addr) 767 var ipv4 net.IP 768 if ip != nil { 769 ipv4 = ip.To4() 770 } 771 772 switch { 773 case ipv4 != nil && (qType == dns.TypeANY || qType == dns.TypeA): 774 records = append(records, &dns.A{ 775 Hdr: dns.RR_Header{ 776 Name: qName, 777 Rrtype: dns.TypeA, 778 Class: dns.ClassINET, 779 Ttl: uint32(ttl / time.Second), 780 }, 781 A: ip, 782 }) 783 784 case ip != nil && ipv4 == nil && (qType == dns.TypeANY || qType == dns.TypeAAAA): 785 records = append(records, &dns.AAAA{ 786 Hdr: dns.RR_Header{ 787 Name: qName, 788 Rrtype: dns.TypeAAAA, 789 Class: dns.ClassINET, 790 Ttl: uint32(ttl / time.Second), 791 }, 792 AAAA: ip, 793 }) 794 795 case ip == nil && (qType == dns.TypeANY || qType == dns.TypeCNAME || 796 qType == dns.TypeA || qType == dns.TypeAAAA || qType == dns.TypeTXT): 797 // Get the CNAME 798 cnRec := &dns.CNAME{ 799 Hdr: dns.RR_Header{ 800 Name: qName, 801 Rrtype: dns.TypeCNAME, 802 Class: dns.ClassINET, 803 Ttl: uint32(ttl / time.Second), 804 }, 805 Target: dns.Fqdn(addr), 806 } 807 records = append(records, cnRec) 808 809 // Recurse 810 more := d.resolveCNAME(cnRec.Target, maxRecursionLevel) 811 extra := 0 812 MORE_REC: 813 for _, rr := range more { 814 switch rr.Header().Rrtype { 815 case dns.TypeCNAME, dns.TypeA, dns.TypeAAAA, dns.TypeTXT: 816 records = append(records, rr) 817 extra++ 818 if extra == maxRecurseRecords && !edns { 819 break MORE_REC 820 } 821 } 822 } 823 } 824 825 if node != nil && generateMeta { 826 for key, value := range node.Meta { 827 txt := value 828 if !strings.HasPrefix(strings.ToLower(key), "rfc1035-") { 829 txt = encodeKVasRFC1464(key, value) 830 } 831 832 meta = append(meta, &dns.TXT{ 833 Hdr: dns.RR_Header{ 834 Name: qName, 835 Rrtype: dns.TypeTXT, 836 Class: dns.ClassINET, 837 Ttl: uint32(ttl / time.Second), 838 }, 839 Txt: []string{txt}, 840 }) 841 } 842 } 843 844 return records, meta 845 } 846 847 // indexRRs populates a map which indexes a given list of RRs by name. NOTE that 848 // the names are all squashed to lower case so we can perform case-insensitive 849 // lookups; the RRs are not modified. 850 func indexRRs(rrs []dns.RR, index map[string]dns.RR) { 851 for _, rr := range rrs { 852 name := strings.ToLower(rr.Header().Name) 853 if _, ok := index[name]; !ok { 854 index[name] = rr 855 } 856 } 857 } 858 859 // syncExtra takes a DNS response message and sets the extra data to the most 860 // minimal set needed to cover the answer data. A pre-made index of RRs is given 861 // so that can be re-used between calls. This assumes that the extra data is 862 // only used to provide info for SRV records. If that's not the case, then this 863 // will wipe out any additional data. 864 func syncExtra(index map[string]dns.RR, resp *dns.Msg) { 865 extra := make([]dns.RR, 0, len(resp.Answer)) 866 resolved := make(map[string]struct{}, len(resp.Answer)) 867 for _, ansRR := range resp.Answer { 868 srv, ok := ansRR.(*dns.SRV) 869 if !ok { 870 continue 871 } 872 873 // Note that we always use lower case when using the index so 874 // that compares are not case-sensitive. We don't alter the actual 875 // RRs we add into the extra section, however. 876 target := strings.ToLower(srv.Target) 877 878 RESOLVE: 879 if _, ok := resolved[target]; ok { 880 continue 881 } 882 resolved[target] = struct{}{} 883 884 extraRR, ok := index[target] 885 if ok { 886 extra = append(extra, extraRR) 887 if cname, ok := extraRR.(*dns.CNAME); ok { 888 target = strings.ToLower(cname.Target) 889 goto RESOLVE 890 } 891 } 892 } 893 resp.Extra = extra 894 } 895 896 // dnsBinaryTruncate find the optimal number of records using a fast binary search and return 897 // it in order to return a DNS answer lower than maxSize parameter. 898 func dnsBinaryTruncate(resp *dns.Msg, maxSize int, index map[string]dns.RR, hasExtra bool) int { 899 originalAnswser := resp.Answer 900 startIndex := 0 901 endIndex := len(resp.Answer) + 1 902 for endIndex-startIndex > 1 { 903 median := startIndex + (endIndex-startIndex)/2 904 905 resp.Answer = originalAnswser[:median] 906 if hasExtra { 907 syncExtra(index, resp) 908 } 909 aLen := resp.Len() 910 if aLen <= maxSize { 911 if maxSize-aLen < 10 { 912 // We are good, increasing will go out of bounds 913 return median 914 } 915 startIndex = median 916 } else { 917 endIndex = median 918 } 919 } 920 return startIndex 921 } 922 923 // trimTCPResponse limit the MaximumSize of messages to 64k as it is the limit 924 // of DNS responses 925 func (d *DNSServer) trimTCPResponse(req, resp *dns.Msg) (trimmed bool) { 926 hasExtra := len(resp.Extra) > 0 927 // There is some overhead, 65535 does not work 928 maxSize := 65523 // 64k - 12 bytes DNS raw overhead 929 930 // We avoid some function calls and allocations by only handling the 931 // extra data when necessary. 932 var index map[string]dns.RR 933 originalSize := resp.Len() 934 originalNumRecords := len(resp.Answer) 935 936 // It is not possible to return more than 4k records even with compression 937 // Since we are performing binary search it is not a big deal, but it 938 // improves a bit performance, even with binary search 939 truncateAt := 4096 940 if req.Question[0].Qtype == dns.TypeSRV { 941 // More than 1024 SRV records do not fit in 64k 942 truncateAt = 1024 943 } 944 if len(resp.Answer) > truncateAt { 945 resp.Answer = resp.Answer[:truncateAt] 946 } 947 if hasExtra { 948 index = make(map[string]dns.RR, len(resp.Extra)) 949 indexRRs(resp.Extra, index) 950 } 951 truncated := false 952 953 // This enforces the given limit on 64k, the max limit for DNS messages 954 for len(resp.Answer) > 1 && resp.Len() > maxSize { 955 truncated = true 956 // More than 100 bytes, find with a binary search 957 if resp.Len()-maxSize > 100 { 958 bestIndex := dnsBinaryTruncate(resp, maxSize, index, hasExtra) 959 resp.Answer = resp.Answer[:bestIndex] 960 } else { 961 resp.Answer = resp.Answer[:len(resp.Answer)-1] 962 } 963 if hasExtra { 964 syncExtra(index, resp) 965 } 966 } 967 if truncated { 968 d.logger.Printf("[DEBUG] dns: TCP answer to %v too large truncated recs:=%d/%d, size:=%d/%d", 969 req.Question, 970 len(resp.Answer), originalNumRecords, resp.Len(), originalSize) 971 } 972 return truncated 973 } 974 975 // trimUDPResponse makes sure a UDP response is not longer than allowed by RFC 976 // 1035. Enforce an arbitrary limit that can be further ratcheted down by 977 // config, and then make sure the response doesn't exceed 512 bytes. Any extra 978 // records will be trimmed along with answers. 979 func trimUDPResponse(req, resp *dns.Msg, udpAnswerLimit int) (trimmed bool) { 980 numAnswers := len(resp.Answer) 981 hasExtra := len(resp.Extra) > 0 982 maxSize := defaultMaxUDPSize 983 984 // Update to the maximum edns size 985 if edns := req.IsEdns0(); edns != nil { 986 if size := edns.UDPSize(); size > uint16(maxSize) { 987 maxSize = int(size) 988 } 989 } 990 991 // We avoid some function calls and allocations by only handling the 992 // extra data when necessary. 993 var index map[string]dns.RR 994 if hasExtra { 995 index = make(map[string]dns.RR, len(resp.Extra)) 996 indexRRs(resp.Extra, index) 997 } 998 999 // This cuts UDP responses to a useful but limited number of responses. 1000 maxAnswers := lib.MinInt(maxUDPAnswerLimit, udpAnswerLimit) 1001 compress := resp.Compress 1002 if maxSize == defaultMaxUDPSize && numAnswers > maxAnswers { 1003 // We disable computation of Len ONLY for non-eDNS request (512 bytes) 1004 resp.Compress = false 1005 resp.Answer = resp.Answer[:maxAnswers] 1006 if hasExtra { 1007 syncExtra(index, resp) 1008 } 1009 } 1010 1011 // This enforces the given limit on the number bytes. The default is 512 as 1012 // per the RFC, but EDNS0 allows for the user to specify larger sizes. Note 1013 // that we temporarily switch to uncompressed so that we limit to a response 1014 // that will not exceed 512 bytes uncompressed, which is more conservative and 1015 // will allow our responses to be compliant even if some downstream server 1016 // uncompresses them. 1017 // Even when size is too big for one single record, try to send it anyway 1018 // (useful for 512 bytes messages) 1019 for len(resp.Answer) > 1 && resp.Len() > maxSize { 1020 // More than 100 bytes, find with a binary search 1021 if resp.Len()-maxSize > 100 { 1022 bestIndex := dnsBinaryTruncate(resp, maxSize, index, hasExtra) 1023 resp.Answer = resp.Answer[:bestIndex] 1024 } else { 1025 resp.Answer = resp.Answer[:len(resp.Answer)-1] 1026 } 1027 if hasExtra { 1028 syncExtra(index, resp) 1029 } 1030 } 1031 // For 512 non-eDNS responses, while we compute size non-compressed, 1032 // we send result compressed 1033 resp.Compress = compress 1034 1035 return len(resp.Answer) < numAnswers 1036 } 1037 1038 // trimDNSResponse will trim the response for UDP and TCP 1039 func (d *DNSServer) trimDNSResponse(network string, req, resp *dns.Msg) (trimmed bool) { 1040 if network != "tcp" { 1041 trimmed = trimUDPResponse(req, resp, d.config.UDPAnswerLimit) 1042 } else { 1043 trimmed = d.trimTCPResponse(req, resp) 1044 } 1045 // Flag that there are more records to return in the UDP response 1046 if trimmed && d.config.EnableTruncate { 1047 resp.Truncated = true 1048 } 1049 return trimmed 1050 } 1051 1052 // lookupServiceNodes returns nodes with a given service. 1053 func (d *DNSServer) lookupServiceNodes(datacenter, service, tag string, connect bool, maxRecursionLevel int) (structs.IndexedCheckServiceNodes, error) { 1054 args := structs.ServiceSpecificRequest{ 1055 Connect: connect, 1056 Datacenter: datacenter, 1057 ServiceName: service, 1058 ServiceTags: []string{tag}, 1059 TagFilter: tag != "", 1060 QueryOptions: structs.QueryOptions{ 1061 Token: d.agent.tokens.UserToken(), 1062 AllowStale: d.config.AllowStale, 1063 MaxAge: d.config.CacheMaxAge, 1064 }, 1065 } 1066 1067 var out structs.IndexedCheckServiceNodes 1068 1069 if d.config.UseCache { 1070 raw, m, err := d.agent.cache.Get(cachetype.HealthServicesName, &args) 1071 if err != nil { 1072 return out, err 1073 } 1074 reply, ok := raw.(*structs.IndexedCheckServiceNodes) 1075 if !ok { 1076 // This should never happen, but we want to protect against panics 1077 return out, fmt.Errorf("internal error: response type not correct") 1078 } 1079 d.logger.Printf("[TRACE] dns: cache hit: %v for service %s", m.Hit, service) 1080 1081 out = *reply 1082 } else { 1083 if err := d.agent.RPC("Health.ServiceNodes", &args, &out); err != nil { 1084 return out, err 1085 } 1086 } 1087 1088 if args.AllowStale && out.LastContact > staleCounterThreshold { 1089 metrics.IncrCounter([]string{"dns", "stale_queries"}, 1) 1090 } 1091 1092 // redo the request the response was too stale 1093 if args.AllowStale && out.LastContact > d.config.MaxStale { 1094 args.AllowStale = false 1095 d.logger.Printf("[WARN] dns: Query results too stale, re-requesting") 1096 1097 if err := d.agent.RPC("Health.ServiceNodes", &args, &out); err != nil { 1098 return structs.IndexedCheckServiceNodes{}, err 1099 } 1100 } 1101 1102 // Filter out any service nodes due to health checks 1103 // We copy the slice to avoid modifying the result if it comes from the cache 1104 nodes := make(structs.CheckServiceNodes, len(out.Nodes)) 1105 copy(nodes, out.Nodes) 1106 out.Nodes = nodes.Filter(d.config.OnlyPassing) 1107 return out, nil 1108 } 1109 1110 // serviceLookup is used to handle a service query 1111 func (d *DNSServer) serviceLookup(network, datacenter, service, tag string, connect bool, req, resp *dns.Msg, maxRecursionLevel int) { 1112 out, err := d.lookupServiceNodes(datacenter, service, tag, connect, maxRecursionLevel) 1113 if err != nil { 1114 d.logger.Printf("[ERR] dns: rpc error: %v", err) 1115 resp.SetRcode(req, dns.RcodeServerFailure) 1116 return 1117 } 1118 1119 // If we have no nodes, return not found! 1120 if len(out.Nodes) == 0 { 1121 d.addSOA(resp) 1122 resp.SetRcode(req, dns.RcodeNameError) 1123 return 1124 } 1125 1126 // Perform a random shuffle 1127 out.Nodes.Shuffle() 1128 1129 // Determine the TTL 1130 ttl, _ := d.GetTTLForService(service) 1131 1132 // Add various responses depending on the request 1133 qType := req.Question[0].Qtype 1134 if qType == dns.TypeSRV { 1135 d.serviceSRVRecords(datacenter, out.Nodes, req, resp, ttl, maxRecursionLevel) 1136 } else { 1137 d.serviceNodeRecords(datacenter, out.Nodes, req, resp, ttl, maxRecursionLevel) 1138 } 1139 1140 d.trimDNSResponse(network, req, resp) 1141 1142 // If the answer is empty and the response isn't truncated, return not found 1143 if len(resp.Answer) == 0 && !resp.Truncated { 1144 d.addSOA(resp) 1145 return 1146 } 1147 } 1148 1149 func ednsSubnetForRequest(req *dns.Msg) *dns.EDNS0_SUBNET { 1150 // IsEdns0 returns the EDNS RR if present or nil otherwise 1151 edns := req.IsEdns0() 1152 1153 if edns == nil { 1154 return nil 1155 } 1156 1157 for _, o := range edns.Option { 1158 if subnet, ok := o.(*dns.EDNS0_SUBNET); ok { 1159 return subnet 1160 } 1161 } 1162 1163 return nil 1164 } 1165 1166 // preparedQueryLookup is used to handle a prepared query. 1167 func (d *DNSServer) preparedQueryLookup(network, datacenter, query string, remoteAddr net.Addr, req, resp *dns.Msg, maxRecursionLevel int) { 1168 // Execute the prepared query. 1169 args := structs.PreparedQueryExecuteRequest{ 1170 Datacenter: datacenter, 1171 QueryIDOrName: query, 1172 QueryOptions: structs.QueryOptions{ 1173 Token: d.agent.tokens.UserToken(), 1174 AllowStale: d.config.AllowStale, 1175 MaxAge: d.config.CacheMaxAge, 1176 }, 1177 1178 // Always pass the local agent through. In the DNS interface, there 1179 // is no provision for passing additional query parameters, so we 1180 // send the local agent's data through to allow distance sorting 1181 // relative to ourself on the server side. 1182 Agent: structs.QuerySource{ 1183 Datacenter: d.agent.config.Datacenter, 1184 Segment: d.agent.config.SegmentName, 1185 Node: d.agent.config.NodeName, 1186 }, 1187 } 1188 1189 subnet := ednsSubnetForRequest(req) 1190 1191 if subnet != nil { 1192 args.Source.Ip = subnet.Address.String() 1193 } else { 1194 switch v := remoteAddr.(type) { 1195 case *net.UDPAddr: 1196 args.Source.Ip = v.IP.String() 1197 case *net.TCPAddr: 1198 args.Source.Ip = v.IP.String() 1199 case *net.IPAddr: 1200 args.Source.Ip = v.IP.String() 1201 } 1202 } 1203 1204 out, err := d.lookupPreparedQuery(args) 1205 1206 // If they give a bogus query name, treat that as a name error, 1207 // not a full on server error. We have to use a string compare 1208 // here since the RPC layer loses the type information. 1209 if err != nil && err.Error() == consul.ErrQueryNotFound.Error() { 1210 d.addSOA(resp) 1211 resp.SetRcode(req, dns.RcodeNameError) 1212 return 1213 } else if err != nil { 1214 resp.SetRcode(req, dns.RcodeServerFailure) 1215 return 1216 } 1217 1218 // TODO (slackpad) - What's a safe limit we can set here? It seems like 1219 // with dup filtering done at this level we need to get everything to 1220 // match the previous behavior. We can optimize by pushing more filtering 1221 // into the query execution, but for now I think we need to get the full 1222 // response. We could also choose a large arbitrary number that will 1223 // likely work in practice, like 10*maxUDPAnswerLimit which should help 1224 // reduce bandwidth if there are thousands of nodes available. 1225 1226 // Determine the TTL. The parse should never fail since we vet it when 1227 // the query is created, but we check anyway. If the query didn't 1228 // specify a TTL then we will try to use the agent's service-specific 1229 // TTL configs. 1230 var ttl time.Duration 1231 if out.DNS.TTL != "" { 1232 var err error 1233 ttl, err = time.ParseDuration(out.DNS.TTL) 1234 if err != nil { 1235 d.logger.Printf("[WARN] dns: Failed to parse TTL '%s' for prepared query '%s', ignoring", out.DNS.TTL, query) 1236 } 1237 } else if d.config.ServiceTTL != nil { 1238 ttl, _ = d.GetTTLForService(out.Service) 1239 } 1240 1241 // If we have no nodes, return not found! 1242 if len(out.Nodes) == 0 { 1243 d.addSOA(resp) 1244 resp.SetRcode(req, dns.RcodeNameError) 1245 return 1246 } 1247 1248 // Add various responses depending on the request. 1249 qType := req.Question[0].Qtype 1250 if qType == dns.TypeSRV { 1251 d.serviceSRVRecords(out.Datacenter, out.Nodes, req, resp, ttl, maxRecursionLevel) 1252 } else { 1253 d.serviceNodeRecords(out.Datacenter, out.Nodes, req, resp, ttl, maxRecursionLevel) 1254 } 1255 1256 d.trimDNSResponse(network, req, resp) 1257 1258 // If the answer is empty and the response isn't truncated, return not found 1259 if len(resp.Answer) == 0 && !resp.Truncated { 1260 d.addSOA(resp) 1261 return 1262 } 1263 } 1264 1265 func (d *DNSServer) lookupPreparedQuery(args structs.PreparedQueryExecuteRequest) (*structs.PreparedQueryExecuteResponse, error) { 1266 var out structs.PreparedQueryExecuteResponse 1267 1268 RPC: 1269 if d.config.UseCache { 1270 raw, m, err := d.agent.cache.Get(cachetype.PreparedQueryName, &args) 1271 if err != nil { 1272 return nil, err 1273 } 1274 reply, ok := raw.(*structs.PreparedQueryExecuteResponse) 1275 if !ok { 1276 // This should never happen, but we want to protect against panics 1277 return nil, err 1278 } 1279 1280 d.logger.Printf("[TRACE] dns: cache hit: %v for prepared query %s", m.Hit, args.QueryIDOrName) 1281 1282 out = *reply 1283 } else { 1284 if err := d.agent.RPC("PreparedQuery.Execute", &args, &out); err != nil { 1285 return nil, err 1286 } 1287 } 1288 1289 // Verify that request is not too stale, redo the request. 1290 if args.AllowStale { 1291 if out.LastContact > d.config.MaxStale { 1292 args.AllowStale = false 1293 d.logger.Printf("[WARN] dns: Query results too stale, re-requesting") 1294 goto RPC 1295 } else if out.LastContact > staleCounterThreshold { 1296 metrics.IncrCounter([]string{"dns", "stale_queries"}, 1) 1297 } 1298 } 1299 1300 return &out, nil 1301 } 1302 1303 // serviceNodeRecords is used to add the node records for a service lookup 1304 func (d *DNSServer) serviceNodeRecords(dc string, nodes structs.CheckServiceNodes, req, resp *dns.Msg, ttl time.Duration, maxRecursionLevel int) { 1305 qName := req.Question[0].Name 1306 qType := req.Question[0].Qtype 1307 handled := make(map[string]struct{}) 1308 edns := req.IsEdns0() != nil 1309 var answerCNAME []dns.RR = nil 1310 1311 count := 0 1312 for _, node := range nodes { 1313 // Start with the translated address but use the service address, 1314 // if specified. 1315 addr := d.agent.TranslateAddress(dc, node.Node.Address, node.Node.TaggedAddresses) 1316 if node.Service.Address != "" { 1317 addr = node.Service.Address 1318 } 1319 1320 // If the service address is a CNAME for the service we are looking 1321 // for then use the node address. 1322 if qName == strings.TrimSuffix(addr, ".")+"." { 1323 addr = node.Node.Address 1324 } 1325 1326 // Avoid duplicate entries, possible if a node has 1327 // the same service on multiple ports, etc. 1328 if _, ok := handled[addr]; ok { 1329 continue 1330 } 1331 handled[addr] = struct{}{} 1332 1333 generateMeta := false 1334 metaInAnswer := false 1335 if qType == dns.TypeANY || qType == dns.TypeTXT { 1336 generateMeta = true 1337 metaInAnswer = true 1338 } else if d.config.NodeMetaTXT { 1339 generateMeta = true 1340 } 1341 1342 // Add the node record 1343 had_answer := false 1344 records, meta := d.formatNodeRecord(node.Node, addr, qName, qType, ttl, edns, maxRecursionLevel, generateMeta) 1345 if records != nil { 1346 switch records[0].(type) { 1347 case *dns.CNAME: 1348 // keep track of the first CNAME + associated RRs but don't add to the resp.Answer yet 1349 // this will only be added if no non-CNAME RRs are found 1350 if len(answerCNAME) == 0 { 1351 answerCNAME = records 1352 } 1353 default: 1354 resp.Answer = append(resp.Answer, records...) 1355 had_answer = true 1356 } 1357 } 1358 1359 if meta != nil && generateMeta && metaInAnswer { 1360 resp.Answer = append(resp.Answer, meta...) 1361 had_answer = true 1362 } else if meta != nil && generateMeta { 1363 resp.Extra = append(resp.Extra, meta...) 1364 } 1365 1366 if had_answer { 1367 count++ 1368 if count == d.config.ARecordLimit { 1369 // We stop only if greater than 0 or we reached the limit 1370 return 1371 } 1372 } 1373 } 1374 1375 if len(resp.Answer) == 0 && len(answerCNAME) > 0 { 1376 resp.Answer = answerCNAME 1377 } 1378 } 1379 1380 func findWeight(node structs.CheckServiceNode) int { 1381 // By default, when only_passing is false, warning and passing nodes are returned 1382 // Those values will be used if using a client with support while server has no 1383 // support for weights 1384 weightPassing := 1 1385 weightWarning := 1 1386 if node.Service.Weights != nil { 1387 weightPassing = node.Service.Weights.Passing 1388 weightWarning = node.Service.Weights.Warning 1389 } 1390 serviceChecks := make(api.HealthChecks, 0) 1391 for _, c := range node.Checks { 1392 if c.ServiceName == node.Service.Service || c.ServiceName == "" { 1393 healthCheck := &api.HealthCheck{ 1394 Node: c.Node, 1395 CheckID: string(c.CheckID), 1396 Name: c.Name, 1397 Status: c.Status, 1398 Notes: c.Notes, 1399 Output: c.Output, 1400 ServiceID: c.ServiceID, 1401 ServiceName: c.ServiceName, 1402 ServiceTags: c.ServiceTags, 1403 } 1404 serviceChecks = append(serviceChecks, healthCheck) 1405 } 1406 } 1407 status := serviceChecks.AggregatedStatus() 1408 switch status { 1409 case api.HealthWarning: 1410 return weightWarning 1411 case api.HealthPassing: 1412 return weightPassing 1413 case api.HealthMaint: 1414 // Not used in theory 1415 return 0 1416 case api.HealthCritical: 1417 // Should not happen since already filtered 1418 return 0 1419 default: 1420 // When non-standard status, return 1 1421 return 1 1422 } 1423 } 1424 1425 // serviceARecords is used to add the SRV records for a service lookup 1426 func (d *DNSServer) serviceSRVRecords(dc string, nodes structs.CheckServiceNodes, req, resp *dns.Msg, ttl time.Duration, maxRecursionLevel int) { 1427 handled := make(map[string]struct{}) 1428 edns := req.IsEdns0() != nil 1429 1430 for _, node := range nodes { 1431 // Avoid duplicate entries, possible if a node has 1432 // the same service the same port, etc. 1433 tuple := fmt.Sprintf("%s:%s:%d", node.Node.Node, node.Service.Address, node.Service.Port) 1434 if _, ok := handled[tuple]; ok { 1435 continue 1436 } 1437 handled[tuple] = struct{}{} 1438 1439 weight := findWeight(node) 1440 // Add the SRV record 1441 srvRec := &dns.SRV{ 1442 Hdr: dns.RR_Header{ 1443 Name: req.Question[0].Name, 1444 Rrtype: dns.TypeSRV, 1445 Class: dns.ClassINET, 1446 Ttl: uint32(ttl / time.Second), 1447 }, 1448 Priority: 1, 1449 Weight: uint16(weight), 1450 Port: uint16(node.Service.Port), 1451 Target: fmt.Sprintf("%s.node.%s.%s", node.Node.Node, dc, d.domain), 1452 } 1453 resp.Answer = append(resp.Answer, srvRec) 1454 1455 // Start with the translated address but use the service address, 1456 // if specified. 1457 addr := d.agent.TranslateAddress(dc, node.Node.Address, node.Node.TaggedAddresses) 1458 if node.Service.Address != "" { 1459 addr = node.Service.Address 1460 } 1461 1462 // Add the extra record 1463 records, meta := d.formatNodeRecord(node.Node, addr, srvRec.Target, dns.TypeANY, ttl, edns, maxRecursionLevel, d.config.NodeMetaTXT) 1464 if len(records) > 0 { 1465 // Use the node address if it doesn't differ from the service address 1466 if addr == node.Node.Address { 1467 resp.Extra = append(resp.Extra, records...) 1468 } else { 1469 // If it differs from the service address, give a special response in the 1470 // 'addr.consul' domain with the service IP encoded in it. We have to do 1471 // this because we can't put an IP in the target field of an SRV record. 1472 switch record := records[0].(type) { 1473 // IPv4 1474 case *dns.A: 1475 addr := hex.EncodeToString(record.A) 1476 1477 // Take the last 8 chars (4 bytes) of the encoded address to avoid junk bytes 1478 srvRec.Target = fmt.Sprintf("%s.addr.%s.%s", addr[len(addr)-(net.IPv4len*2):], dc, d.domain) 1479 record.Hdr.Name = srvRec.Target 1480 resp.Extra = append(resp.Extra, record) 1481 1482 // IPv6 1483 case *dns.AAAA: 1484 srvRec.Target = fmt.Sprintf("%s.addr.%s.%s", hex.EncodeToString(record.AAAA), dc, d.domain) 1485 record.Hdr.Name = srvRec.Target 1486 resp.Extra = append(resp.Extra, record) 1487 1488 // Something else (probably a CNAME; just add the records). 1489 default: 1490 resp.Extra = append(resp.Extra, records...) 1491 } 1492 } 1493 1494 if meta != nil && d.config.NodeMetaTXT { 1495 resp.Extra = append(resp.Extra, meta...) 1496 } 1497 } 1498 } 1499 } 1500 1501 // handleRecurse is used to handle recursive DNS queries 1502 func (d *DNSServer) handleRecurse(resp dns.ResponseWriter, req *dns.Msg) { 1503 q := req.Question[0] 1504 network := "udp" 1505 defer func(s time.Time) { 1506 d.logger.Printf("[DEBUG] dns: request for %v (%s) (%v) from client %s (%s)", 1507 q, network, time.Since(s), resp.RemoteAddr().String(), 1508 resp.RemoteAddr().Network()) 1509 }(time.Now()) 1510 1511 // Switch to TCP if the client is 1512 if _, ok := resp.RemoteAddr().(*net.TCPAddr); ok { 1513 network = "tcp" 1514 } 1515 1516 // Recursively resolve 1517 c := &dns.Client{Net: network, Timeout: d.config.RecursorTimeout} 1518 var r *dns.Msg 1519 var rtt time.Duration 1520 var err error 1521 for _, recursor := range d.recursors { 1522 r, rtt, err = c.Exchange(req, recursor) 1523 // Check if the response is valid and has the desired Response code 1524 if r != nil && (r.Rcode != dns.RcodeSuccess && r.Rcode != dns.RcodeNameError) { 1525 d.logger.Printf("[DEBUG] dns: recurse RTT for %v (%v) Recursor queried: %v Status returned: %v", q, rtt, recursor, dns.RcodeToString[r.Rcode]) 1526 // If we still have recursors to forward the query to, 1527 // we move forward onto the next one else the loop ends 1528 continue 1529 } else if err == nil || err == dns.ErrTruncated { 1530 // Compress the response; we don't know if the incoming 1531 // response was compressed or not, so by not compressing 1532 // we might generate an invalid packet on the way out. 1533 r.Compress = !d.disableCompression.Load().(bool) 1534 1535 // Forward the response 1536 d.logger.Printf("[DEBUG] dns: recurse RTT for %v (%v) Recursor queried: %v", q, rtt, recursor) 1537 if err := resp.WriteMsg(r); err != nil { 1538 d.logger.Printf("[WARN] dns: failed to respond: %v", err) 1539 } 1540 return 1541 } 1542 d.logger.Printf("[ERR] dns: recurse failed: %v", err) 1543 } 1544 1545 // If all resolvers fail, return a SERVFAIL message 1546 d.logger.Printf("[ERR] dns: all resolvers failed for %v from client %s (%s)", 1547 q, resp.RemoteAddr().String(), resp.RemoteAddr().Network()) 1548 m := &dns.Msg{} 1549 m.SetReply(req) 1550 m.Compress = !d.disableCompression.Load().(bool) 1551 m.RecursionAvailable = true 1552 m.SetRcode(req, dns.RcodeServerFailure) 1553 if edns := req.IsEdns0(); edns != nil { 1554 setEDNS(req, m, true) 1555 } 1556 resp.WriteMsg(m) 1557 } 1558 1559 // resolveCNAME is used to recursively resolve CNAME records 1560 func (d *DNSServer) resolveCNAME(name string, maxRecursionLevel int) []dns.RR { 1561 // If the CNAME record points to a Consul address, resolve it internally 1562 // Convert query to lowercase because DNS is case insensitive; d.domain is 1563 // already converted 1564 1565 if strings.HasSuffix(strings.ToLower(name), "."+d.domain) { 1566 if maxRecursionLevel < 1 { 1567 d.logger.Printf("[ERR] dns: Infinite recursion detected for %s, won't perform any CNAME resolution.", name) 1568 return nil 1569 } 1570 req := &dns.Msg{} 1571 resp := &dns.Msg{} 1572 1573 req.SetQuestion(name, dns.TypeANY) 1574 d.doDispatch("udp", nil, req, resp, maxRecursionLevel-1) 1575 1576 return resp.Answer 1577 } 1578 1579 // Do nothing if we don't have a recursor 1580 if len(d.recursors) == 0 { 1581 return nil 1582 } 1583 1584 // Ask for any A records 1585 m := new(dns.Msg) 1586 m.SetQuestion(name, dns.TypeA) 1587 1588 // Make a DNS lookup request 1589 c := &dns.Client{Net: "udp", Timeout: d.config.RecursorTimeout} 1590 var r *dns.Msg 1591 var rtt time.Duration 1592 var err error 1593 for _, recursor := range d.recursors { 1594 r, rtt, err = c.Exchange(m, recursor) 1595 if err == nil { 1596 d.logger.Printf("[DEBUG] dns: cname recurse RTT for %v (%v)", name, rtt) 1597 return r.Answer 1598 } 1599 d.logger.Printf("[ERR] dns: cname recurse failed for %v: %v", name, err) 1600 } 1601 d.logger.Printf("[ERR] dns: all resolvers failed for %v", name) 1602 return nil 1603 }