// Copyright (C) Internet Systems Consortium, Inc. ("ISC")
//
// SPDX-License-Identifier: MPL-2.0
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//
// See the COPYRIGHT file distributed with this work for additional
// information regarding copyright ownership.

// dnstap: flexible, structured event replication format for DNS software
//
// This file contains the protobuf schemas for the "dnstap" structured event
// replication format for DNS software.

// Written in 2013-2014 by Farsight Security, Inc.
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this file to the public
// domain worldwide. This file is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along
// with this file. If not, see:
//
// <http://creativecommons.org/publicdomain/zero/1.0/>.

syntax = "proto2";
package dnstap;

// "Dnstap": this is the top-level dnstap type, which is a "union" type that
// contains other kinds of dnstap payloads, although currently only one type
// of dnstap payload is defined.
// See: https://developers.google.com/protocol-buffers/docs/techniques#union
message Dnstap {
    // DNS server identity.
    // If enabled, this is the identity string of the DNS server which generated
    // this message. Typically this would be the same string as returned by an
    // "NSID" (RFC 5001) query.
    optional bytes      identity = 1;

    // DNS server version.
    // If enabled, this is the version string of the DNS server which generated
    // this message. Typically this would be the same string as returned by a
    // "version.bind" query.
    optional bytes      version = 2;

    // Extra data for this payload.
    // This field can be used for adding an arbitrary byte-string annotation to
    // the payload. No encoding or interpretation is applied or enforced.
    optional bytes      extra = 3;

    // Identifies which field below is filled in.
    enum Type {
        MESSAGE = 1;
    }
    required Type       type = 15;

    // One of the following will be filled in.
    optional Message    message = 14;
}

// SocketFamily: the network protocol family of a socket. This specifies how
// to interpret "network address" fields.
enum SocketFamily {
    INET = 1;   // IPv4 (RFC 791)
    INET6 = 2;  // IPv6 (RFC 2460)
}

// SocketProtocol: the protocol used to transport a DNS message.
enum SocketProtocol {
    UDP = 1;         // DNS over UDP transport (RFC 1035 section 4.2.1)
    TCP = 2;         // DNS over TCP transport (RFC 1035 section 4.2.2)
    DOT = 3;         // DNS over TLS (RFC 7858)
    DOH = 4;         // DNS over HTTPS (RFC 8484)
    DNSCryptUDP = 5; // DNSCrypt over UDP (https://dnscrypt.info/protocol)
    DNSCryptTCP = 6; // DNSCrypt over TCP (https://dnscrypt.info/protocol)
    DOQ = 7;         // DNS over QUIC (RFC 9250)
}

// Policy: information about any name server operator policy
// applied to the processing of a DNS message.
message Policy {

    // Match: what aspect of the message or message exchange
    // triggered the application of the Policy.
    enum Match {
        QNAME = 1;       // Name in question section of query
        CLIENT_IP = 2;   // Client IP address
        RESPONSE_IP = 3; // Address in A/AAAA RRSet
        NS_NAME = 4;     // Authoritative name server, by name
        NS_IP = 5;       // Authoritative name server, by IP address
    }

    // The Action taken to implement the Policy.
    enum Action {
        NXDOMAIN = 1;   // Respond with NXDOMAIN
        NODATA = 2;     // Respond with empty answer section
        PASS = 3;       // Do not alter the response (passthrough)
        DROP = 4;       // Do not respond.
        TRUNCATE = 5;   // Truncate UDP response, forcing TCP retry
        LOCAL_DATA = 6; // Respond with local data from policy
    }

    // type: the type of policy applied, e.g. "RPZ" for a
    // policy from a Response Policy Zone.
    optional string type = 1;

    // rule: the rule matched by the message.
    //
    // In a RPZ context, this is the owner name of the rule in
    // the Reponse Policy Zone in wire format.
    optional bytes rule = 2;

    // action: the policy action taken in response to the
    // rule match.
    optional Action action = 3;

    // match: the feature of the message exchange which matched the rule.
    optional Match match = 4;

    // The matched value. Format depends on the matched feature .
    optional bytes value = 5;
}

// Message: a wire-format (RFC 1035 section 4) DNS message and associated
// metadata. Applications generating "Message" payloads should follow
// certain requirements based on the MessageType, see below.
message Message {

    // There are eight types of "Message" defined that correspond to the
    // four arrows in the following diagram, slightly modified from RFC 1035
    // section 2:

    //    +---------+               +----------+           +--------+
    //    |         |     query     |          |   query   |        |
    //    | Stub    |-SQ--------CQ->| Recursive|-RQ----AQ->| Auth.  |
    //    | Resolver|               | Server   |           | Name   |
    //    |         |<-SR--------CR-|          |<-RR----AR-| Server |
    //    +---------+    response   |          |  response |        |
    //                              +----------+           +--------+

    // Each arrow has two Type values each, one for each "end" of each arrow,
    // because these are considered to be distinct events. Each end of each
    // arrow on the diagram above has been marked with a two-letter Type
    // mnemonic. Clockwise from upper left, these mnemonic values are:
    //
    //   SQ:        STUB_QUERY
    //   CQ:      CLIENT_QUERY
    //   RQ:    RESOLVER_QUERY
    //   AQ:        AUTH_QUERY
    //   AR:        AUTH_RESPONSE
    //   RR:    RESOLVER_RESPONSE
    //   CR:      CLIENT_RESPONSE
    //   SR:        STUB_RESPONSE

    // Two additional types of "Message" have been defined for the
    // "forwarding" case where an upstream DNS server is responsible for
    // further recursion. These are not shown on the diagram above, but have
    // the following mnemonic values:

    //   FQ:   FORWARDER_QUERY
    //   FR:   FORWARDER_RESPONSE

    // The "Message" Type values are defined below.

    enum Type {
        // AUTH_QUERY is a DNS query message received from a resolver by an
        // authoritative name server, from the perspective of the authoritative
        // name server.
        AUTH_QUERY = 1;

        // AUTH_RESPONSE is a DNS response message sent from an authoritative
        // name server to a resolver, from the perspective of the authoritative
        // name server.
        AUTH_RESPONSE = 2;

        // RESOLVER_QUERY is a DNS query message sent from a resolver to an
        // authoritative name server, from the perspective of the resolver.
        // Resolvers typically clear the RD (recursion desired) bit when
        // sending queries.
        RESOLVER_QUERY = 3;

        // RESOLVER_RESPONSE is a DNS response message received from an
        // authoritative name server by a resolver, from the perspective of
        // the resolver.
        RESOLVER_RESPONSE = 4;

        // CLIENT_QUERY is a DNS query message sent from a client to a DNS
        // server which is expected to perform further recursion, from the
        // perspective of the DNS server. The client may be a stub resolver or
        // forwarder or some other type of software which typically sets the RD
        // (recursion desired) bit when querying the DNS server. The DNS server
        // may be a simple forwarding proxy or it may be a full recursive
        // resolver.
        CLIENT_QUERY = 5;

        // CLIENT_RESPONSE is a DNS response message sent from a DNS server to
        // a client, from the perspective of the DNS server. The DNS server
        // typically sets the RA (recursion available) bit when responding.
        CLIENT_RESPONSE = 6;

        // FORWARDER_QUERY is a DNS query message sent from a downstream DNS
        // server to an upstream DNS server which is expected to perform
        // further recursion, from the perspective of the downstream DNS
        // server.
        FORWARDER_QUERY = 7;

        // FORWARDER_RESPONSE is a DNS response message sent from an upstream
        // DNS server performing recursion to a downstream DNS server, from the
        // perspective of the downstream DNS server.
        FORWARDER_RESPONSE = 8;

        // STUB_QUERY is a DNS query message sent from a stub resolver to a DNS
        // server, from the perspective of the stub resolver.
        STUB_QUERY = 9;

        // STUB_RESPONSE is a DNS response message sent from a DNS server to a
        // stub resolver, from the perspective of the stub resolver.
        STUB_RESPONSE = 10;

        // TOOL_QUERY is a DNS query message sent from a DNS software tool to a
        // DNS server, from the perspective of the tool.
        TOOL_QUERY = 11;

        // TOOL_RESPONSE is a DNS response message received by a DNS software
        // tool from a DNS server, from the perspective of the tool.
        TOOL_RESPONSE = 12;

        // UPDATE_QUERY is a Dynamic DNS Update request (RFC 2136) received
        // by an authoritative name server, from the perspective of the
        // authoritative name server.
        UPDATE_QUERY = 13;

        // UPDATE_RESPONSE is a Dynamic DNS Update response (RFC 2136) sent
        // from an authoritative name server, from the perspective of the
        // authoritative name server.
        UPDATE_RESPONSE = 14;
    }

    // One of the Type values described above.
    required Type               type = 1;

    // One of the SocketFamily values described above.
    optional SocketFamily       socket_family = 2;

    // One of the SocketProtocol values described above.
    optional SocketProtocol     socket_protocol = 3;

    // The network address of the message initiator.
    // For SocketFamily INET, this field is 4 octets (IPv4 address).
    // For SocketFamily INET6, this field is 16 octets (IPv6 address).
    optional bytes              query_address = 4;

    // The network address of the message responder.
    // For SocketFamily INET, this field is 4 octets (IPv4 address).
    // For SocketFamily INET6, this field is 16 octets (IPv6 address).
    optional bytes              response_address = 5;

    // The transport port of the message initiator.
    // This is a 16-bit UDP or TCP port number, depending on SocketProtocol.
    optional uint32             query_port = 6;

    // The transport port of the message responder.
    // This is a 16-bit UDP or TCP port number, depending on SocketProtocol.
    optional uint32             response_port = 7;

    // The time at which the DNS query message was sent or received, depending
    // on whether this is an AUTH_QUERY, RESOLVER_QUERY, or CLIENT_QUERY.
    // This is the number of seconds since the UNIX epoch.
    optional uint64             query_time_sec = 8;

    // The time at which the DNS query message was sent or received.
    // This is the seconds fraction, expressed as a count of nanoseconds.
    optional fixed32            query_time_nsec = 9;

    // The initiator's original wire-format DNS query message, verbatim.
    optional bytes              query_message = 10;

    // The "zone" or "bailiwick" pertaining to the DNS query message.
    // This is a wire-format DNS domain name.
    optional bytes              query_zone = 11;

    // The time at which the DNS response message was sent or received,
    // depending on whether this is an AUTH_RESPONSE, RESOLVER_RESPONSE, or
    // CLIENT_RESPONSE.
    // This is the number of seconds since the UNIX epoch.
    optional uint64             response_time_sec = 12;

    // The time at which the DNS response message was sent or received.
    // This is the seconds fraction, expressed as a count of nanoseconds.
    optional fixed32            response_time_nsec = 13;

    // The responder's original wire-format DNS response message, verbatim.
    optional bytes              response_message = 14;

    // Operator policy applied to the processing of this message, if any.
    optional Policy             policy = 15;
}

// All fields except for 'type' in the Message schema are optional.
// It is recommended that at least the following fields be filled in for
// particular types of Messages.

// AUTH_QUERY:
//      socket_family, socket_protocol
//      query_address, query_port
//      query_message
//      query_time_sec, query_time_nsec

// AUTH_RESPONSE:
//      socket_family, socket_protocol
//      query_address, query_port
//      query_time_sec, query_time_nsec
//      response_message
//      response_time_sec, response_time_nsec

// RESOLVER_QUERY:
//      socket_family, socket_protocol
//      query_message
//      query_time_sec, query_time_nsec
//      query_zone
//      response_address, response_port

// RESOLVER_RESPONSE:
//      socket_family, socket_protocol
//      query_time_sec, query_time_nsec
//      query_zone
//      response_address, response_port
//      response_message
//      response_time_sec, response_time_nsec

// CLIENT_QUERY:
//      socket_family, socket_protocol
//      query_message
//      query_time_sec, query_time_nsec

// CLIENT_RESPONSE:
//      socket_family, socket_protocol
//      query_time_sec, query_time_nsec
//      response_message
//      response_time_sec, response_time_nsec
