// Copyright 2025 Envoy Project Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package envoy.data.dns.v3;

import "envoy/type/matcher/v3/string.proto";

import "google/protobuf/duration.proto";

import "envoy/annotations/deprecation.proto";
import "udpa/annotations/status.proto";
import "udpa/annotations/versioning.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.data.dns.v3";
option java_outer_classname = "DnsTableProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/data/dns/v3;dnsv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: DNS Filter Table Data]
// :ref:`DNS Filter config overview <config_udp_listener_filters_dns_filter>`.

// This message contains the configuration for the DNS Filter if populated
// from the control plane
message DnsTable {
  option (udpa.annotations.versioning).previous_message_type = "envoy.data.dns.v2alpha.DnsTable";

  // This message contains a list of IP addresses returned for a query for a known name
  message AddressList {
    option (udpa.annotations.versioning).previous_message_type =
        "envoy.data.dns.v2alpha.DnsTable.AddressList";

    // This field contains a well formed IP address that is returned in the answer for a
    // name query. The address field can be an IPv4 or IPv6 address. Address family
    // detection is done automatically when Envoy parses the string. Since this field is
    // repeated, Envoy will return as many entries from this list in the DNS response while
    // keeping the response under 512 bytes
    repeated string address = 1 [(validate.rules).repeated = {
      min_items: 1
      items {string {min_len: 3}}
    }];
  }

  // Specify the service protocol using a numeric or string value
  message DnsServiceProtocol {
    oneof protocol_config {
      option (validate.required) = true;

      // Specify the protocol number for the service. Envoy will try to resolve the number to
      // the protocol name. For example, 6 will resolve to "tcp". Refer to:
      // https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
      // for protocol names and numbers
      uint32 number = 1 [(validate.rules).uint32 = {lt: 255}];

      // Specify the protocol name for the service.
      string name = 2 [(validate.rules).string = {min_len: 1 well_known_regex: HTTP_HEADER_NAME}];
    }
  }

  // Specify the target for a given DNS service
  // [#next-free-field: 6]
  message DnsServiceTarget {
    // Specify the name of the endpoint for the Service. The name is a hostname or a cluster
    oneof endpoint_type {
      option (validate.required) = true;

      // Use a resolvable hostname as the endpoint for a service.
      string host_name = 1
          [(validate.rules).string = {min_len: 1 well_known_regex: HTTP_HEADER_NAME}];

      // Use a cluster name as the endpoint for a service.
      string cluster_name = 2
          [(validate.rules).string = {min_len: 1 well_known_regex: HTTP_HEADER_NAME}];
    }

    // The priority of the service record target
    uint32 priority = 3 [(validate.rules).uint32 = {lt: 65536}];

    // The weight of the service record target
    uint32 weight = 4 [(validate.rules).uint32 = {lt: 65536}];

    // The port to which the service is bound. This value is optional if the target is a
    // cluster. Setting port to zero in this case makes the filter use the port value
    // from the cluster host
    uint32 port = 5 [(validate.rules).uint32 = {lt: 65536}];
  }

  // This message defines a service selection record returned for a service query in a domain
  message DnsService {
    // The name of the service without the protocol or domain name
    string service_name = 1
        [(validate.rules).string = {min_len: 1 well_known_regex: HTTP_HEADER_NAME}];

    // The service protocol. This can be specified as a string or the numeric value of the protocol
    DnsServiceProtocol protocol = 2;

    // The service entry time to live. This is independent from the DNS Answer record TTL
    google.protobuf.Duration ttl = 3 [(validate.rules).duration = {gte {seconds: 1}}];

    // The list of targets hosting the service
    repeated DnsServiceTarget targets = 4 [(validate.rules).repeated = {min_items: 1}];
  }

  // Define a list of service records for a given service
  message DnsServiceList {
    repeated DnsService services = 1 [(validate.rules).repeated = {min_items: 1}];
  }

  message DnsEndpoint {
    option (udpa.annotations.versioning).previous_message_type =
        "envoy.data.dns.v2alpha.DnsTable.DnsEndpoint";

    oneof endpoint_config {
      option (validate.required) = true;

      // Define a list of addresses to return for the specified endpoint
      AddressList address_list = 1;

      // Define a cluster whose addresses are returned for the specified endpoint
      string cluster_name = 2;

      // Define a DNS Service List for the specified endpoint
      DnsServiceList service_list = 3;
    }
  }

  message DnsVirtualDomain {
    option (udpa.annotations.versioning).previous_message_type =
        "envoy.data.dns.v2alpha.DnsTable.DnsVirtualDomain";

    // A domain name for which Envoy will respond to query requests.
    // Wildcard records are supported on the first label only, e.g. ``*.example.com`` or ``*.subdomain.example.com``.
    // Names such as ``*example.com``, ``subdomain.*.example.com``, ``*subdomain.example.com``, etc
    // are not valid wildcard names and asterisk will be interpreted as a literal ``*`` character.
    // Wildcard records match subdomains on any levels, e.g. ``*.example.com`` will match
    // ``foo.example.com``, ``bar.foo.example.com``, ``baz.bar.foo.example.com``, etc. In case there are multiple
    // wildcard records, the longest wildcard match will be used, e.g. if there are wildcard records for
    // ``*.example.com`` and ``*.foo.example.com`` and the query is for ``bar.foo.example.com``, the latter will be used.
    // Specific records will always take precedence over wildcard records.
    string name = 1 [(validate.rules).string = {min_len: 1 well_known_regex: HTTP_HEADER_NAME}];

    // The configuration containing the method to determine the address of this endpoint
    DnsEndpoint endpoint = 2;

    // Sets the TTL in DNS answers from Envoy returned to the client. The default TTL is 300s
    google.protobuf.Duration answer_ttl = 3 [(validate.rules).duration = {gte {seconds: 30}}];
  }

  // Control how many times Envoy makes an attempt to forward a query to an external DNS server
  uint32 external_retry_count = 1 [(validate.rules).uint32 = {lte: 3}];

  // Fully qualified domain names for which Envoy will respond to DNS queries. By leaving this
  // list empty, Envoy will forward all queries to external resolvers
  repeated DnsVirtualDomain virtual_domains = 2;

  // This field is deprecated and no longer used in Envoy. The filter's behavior has changed
  // internally to use a different data structure allowing the filter to determine whether a
  // query is for known domain without the use of this field.
  //
  // This field serves to help Envoy determine whether it can authoritatively answer a query
  // for a name matching a suffix in this list. If the query name does not match a suffix in
  // this list, Envoy will forward the query to an upstream DNS server
  repeated type.matcher.v3.StringMatcher known_suffixes = 3
      [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"];
}
