/*
 * 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.
 */

#pragma once

#include <inttypes.h>

#include <isc/mem.h>
#include <isc/util.h>

#include <dns/message.h>

/*%< EDNS0 extended DNS errors */
typedef enum ISC_FIXED_ENUM(dns_edecode, uint16_t) {
	// typedef enum ISC_FIXED_ENUM(dns_edecode, uint16_t) {
	DNS_EDE_OTHER = 0,		  /*%< Other Error */
	DNS_EDE_DNSKEYALG = 1,		  /*%< Unsupported DNSKEY Algorithm */
	DNS_EDE_DSDIGESTTYPE = 2,	  /*%< Unsupported DS Digest Type */
	DNS_EDE_STALEANSWER = 3,	  /*%< Stale Answer */
	DNS_EDE_FORGEDANSWER = 4,	  /*%< Forged Answer */
	DNS_EDE_DNSSECINDETERMINATE = 5,  /*%< DNSSEC Indeterminate */
	DNS_EDE_DNSSECBOGUS = 6,	  /*%< DNSSEC Bogus */
	DNS_EDE_SIGNATUREEXPIRED = 7,	  /*%< Signature Expired */
	DNS_EDE_SIGNATURENOTYETVALID = 8, /*%< Signature Not Yet Valid */
	DNS_EDE_DNSKEYMISSING = 9,	  /*%< DNSKEY Missing */
	DNS_EDE_RRSIGSMISSING = 10,	  /*%< RRSIGs Missing */
	DNS_EDE_NOZONEKEYBITSET = 11,	  /*%< No Zone Key Bit Set */
	DNS_EDE_NSECMISSING = 12,	  /*%< NSEC Missing */
	DNS_EDE_CACHEDERROR = 13,	  /*%< Cached Error */
	DNS_EDE_NOTREADY = 14,		  /*%< Not Ready */
	DNS_EDE_BLOCKED = 15,		  /*%< Blocked */
	DNS_EDE_CENSORED = 16,		  /*%< Censored */
	DNS_EDE_FILTERED = 17,		  /*%< Filtered */
	DNS_EDE_PROHIBITED = 18,	  /*%< Prohibited */
	DNS_EDE_STALENXANSWER = 19,	  /*%< Stale NXDomain Answer */
	DNS_EDE_NOTAUTH = 20,		  /*%< Not Authoritative */
	DNS_EDE_NOTSUPPORTED = 21,	  /*%< Not Supported */
	DNS_EDE_NOREACHABLEAUTH = 22,	  /*%< No Reachable Authority */
	DNS_EDE_NETWORKERROR = 23,	  /*%< Network Error */
	DNS_EDE_INVALIDDATA = 24,	  /*%< Invalid Data */
	DNS_EDE_NTA = 33,		  /*%< Negative Trust Anchor */
	DNS_EDE_MAX_CODE,
	DNS_EDE_ENFORCE = UINT16_MAX, /*%< Enforce uint16_t size */
} dns_edecode_t;

STATIC_ASSERT(sizeof(dns_edecode_t) == sizeof(uint16_t),
	      "dns_edecode_t is not uint16_t sized");

/*
 * From RFC 8914:
 * Because long EXTRA-TEXT fields may trigger truncation (which is undesirable
 * given the supplemental nature of EDE), implementers and operators creating
 * EDE options SHOULD avoid lengthy EXTRA-TEXT contents.
 *
 * Following this advice we limit the EXTRA-TEXT length to 64 characters.
 */
#define DNS_EDE_EXTRATEXT_LEN 64

typedef struct dns_edectx dns_edectx_t;
struct dns_edectx {
	int	       magic;
	isc_mem_t     *mctx;
	dns_ednsopt_t *ede[DNS_EDE_MAX_ERRORS];
	uint64_t       edeused;
	size_t	       nextede;
};
/*%<
 * Multiple extended DNS errors (EDE) (defined in RFC 8914) can be raised during
 * a DNS resolution and in various area of the code base. "dns_edectx_t" object
 * abstract and holds pending EDE and the set of dns_ede_ API enable to
 * manipulate its state (adding EDE, transfer to another context, etc.). EDE are
 * internally stored in the wire format, so it can be directly consumed to build
 * the response client message.
 */

STATIC_ASSERT(DNS_EDE_MAX_CODE <=
		      CHAR_BIT * sizeof(((dns_edectx_t *){ NULL })->edeused),
	      "DNS_EDE_MAX_CODE does not fit in the edeused bitmap");
/*
 * Make sure we can fit the currently supported EDE codes in the edeused bitmap.
 */

void
dns_ede_init(isc_mem_t *mctx, dns_edectx_t *edectx);
/*%<
 * Initialize "edectx" so it is valid to use. Can be called after
 * dns_ede_invalidate" is being called to reuse the object.
 *
 * Requires:
 *
 * \li "mctx" to be valid
 * \li "edectx" to be valid
 */

void
dns_ede_reset(dns_edectx_t *edectx);
/*%<
 * Reset "edectx" internal state and free all its EDE from memory. "edectx" is
 * still valid to use, in the same state than after dns_ede_init is called.
 *
 * Requires:
 *
 * \li "edectx" to be valid
 */

void
dns_ede_invalidate(dns_edectx_t *edectx);
/*%<
 * Reset "edectx" and remove its memory context as well as its magic number. It
 * is not valid to use anymore.
 *
 * Requires:
 *
 * \li "edectx" to be valid
 */

void
dns_ede_add(dns_edectx_t *edectx, uint16_t code, const char *text);
/*%<
 * Add a new extended error in "edectx". "code" must be one of the INFO-CODE
 * values defined in RFC8914, see DNS_EDE_ macros above. "text" is optional, it
 * is immediately copied internally if provided.
 *
 * Rules:
 *
 * \li If "text" is non NULL, it must be NULL terminated. If its length is more
 * than DNS_EDE_EXTRATEXT_LEN, it is trucated.
 *
 * \li If an EDE with the same code has already been added to "edectx", the
 * following ones with the same code are ignored.
 *
 * \li If more than DNS_EDE_MAX_ERRORS EDE have been already added to this
 * context, the following ones are ignored.
 *
 * Requires:
 *
 * \li "edectx" to be valid
 * \li "code" to be one of the INFO-CODE defied in RFC8914, see DNS_EDE_ macros.
 */

void
dns_ede_copy(dns_edectx_t *edectx_to, const dns_edectx_t *edectx_from);
/*%<
 * Copy all EDE from "edectx_from" into "edectx_to". If "edectx_to" reaches the
 * maximum number of EDE (see DNS_EDE_MAX_ERRORS), the copy stops and
 * remaining EDE in "edectx_from" are not copied.
 *
 * Rules defined in "dns_ede_add" applies.
 *
 * Requires:
 *
 * \li "edectx_from" to be valid
 * \li "edectx_to" to be valid
 */
