// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 package dns // parsedLabels defines valid DNS labels that are possible for ALL DNS query in Consul. (v1 and v2, CE and ENT) // It is the job of the parser to populate the struct, the routers to call the query processor, // and the query processor to validate is the labels. type parsedLabels struct { Datacenter string Namespace string Partition string Peer string PeerOrDatacenter string // deprecated: use Datacenter or Peer SamenessGroup string } // ParseLabels can parse a DNS query's labels and returns a parsedLabels. // It also does light validation according to invariants across all possible DNS queries for all Consul versions func parseLabels(labels []string) (*parsedLabels, bool) { var result parsedLabels switch len(labels) { case 2, 4, 6: // Supports the following formats: // - [..ns][..ap][..dc] // - . // - [..ns][..ap][..peer] // - [..sg][..ap][..ns] for i := 0; i < len(labels); i += 2 { switch labels[i+1] { case "ns": result.Namespace = labels[i] case "ap": result.Partition = labels[i] case "dc", "cluster": result.Datacenter = labels[i] case "sg": result.SamenessGroup = labels[i] case "peer": result.Peer = labels[i] default: // The only case in which labels[i+1] is allowed to be a value // other than ns, ap, or dc is if n == 2 to support the format: // .. if len(labels) == 2 { result.PeerOrDatacenter = labels[1] result.Namespace = labels[0] return &result, true } return nil, false } } // VALIDATIONS // Return nil result and false boolean when both datacenter and peer are specified. if result.Datacenter != "" && result.Peer != "" { return nil, false } // Validate that this a valid DNS including sg if result.SamenessGroup != "" && (result.Datacenter != "" || result.Peer != "") { return nil, false } return &result, true case 1: result.PeerOrDatacenter = labels[0] return &result, true case 0: return &result, true } return &result, false } // parsePort looks through the query parts for a named port label. // It assumes the only valid input format is["", "port", ""]. // The other expected formats are [""] and ["", ""]. // It is expected that the queryProcessor validates if the label is allowed for the query type. func parsePort(parts []string) string { // The minimum number of parts would be if len(parts) != 3 || parts[1] != "port" { return "" } return parts[0] }