From: Frantisek Tobias Date: Tue, 16 Dec 2025 09:52:32 +0000 (+0100) Subject: config: Add additional QUIC configuration and documentation X-Git-Tag: v6.2.0~2^2~15 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e3a6a8a0eafbe6282cd6a94990b81d0f2d7bdcd6;p=thirdparty%2Fknot-resolver.git config: Add additional QUIC configuration and documentation --- diff --git a/daemon/bindings/net.c b/daemon/bindings/net.c index cb3d7498d..e4f6dcba4 100644 --- a/daemon/bindings/net.c +++ b/daemon/bindings/net.c @@ -8,6 +8,7 @@ #include "contrib/cleanup.h" #include "daemon/network.h" #include "daemon/tls.h" +#include "daemon/quic_common.h" #include "lib/utils.h" #include @@ -620,6 +621,107 @@ static int net_doh_headers(lua_State *L) return 0; } +static int net_quic_max_conns(lua_State *L) +{ + if (kr_fails_assert(the_network)) { + return 0; + } + + // /* Only return current max conns. */ + if (lua_gettop(L) == 0) { + if (!the_network->quic_params) { + return 0; + } + + lua_newtable(L); + lua_pushinteger(L, the_network->quic_params->max_conns); + return 1; + } + + /* Allocate struct if needed */ + if (!the_network->quic_params && quic_configuration_set() != kr_ok()) { + lua_error_p(L, "Out of memory allocating net_quic_params"); + } + + if (lua_gettop(L) != 1 || !lua_isnumber(L, 1)) + lua_error_p(L, "net.quic_max_conns requires one integer value within <1, 4096>"); + + lua_Integer v = lua_tointeger(L, 1); + if (v < 1 || v > 4096) + lua_error_p(L, "net.quic_max_conns must be within <1, 4096>"); + + the_network->quic_params->max_conns = (uint16_t)v; + lua_pushboolean(L, true); + return 1; +} + +static int net_quic_max_streams(lua_State *L) +{ + if (kr_fails_assert(the_network)) { + return 0; + } + + // /* Only return current max streams. */ + if (lua_gettop(L) == 0) { + if (!the_network->quic_params) { + return 0; + } + + lua_newtable(L); + lua_pushinteger(L, the_network->quic_params->max_streams); + return 1; + } + + /* Allocate struct if needed */ + if (!the_network->quic_params && quic_configuration_set() != kr_ok()) { + lua_error_p(L, "Out of memory allocating net_quic_params"); + } + + if (lua_gettop(L) != 1 || !lua_isnumber(L, 1)) + lua_error_p(L, "net.quic_max_streams requires one integer value within <1, 4096>"); + + lua_Integer v = lua_tointeger(L, 1); + if (v < 1 || v > 4096) + lua_error_p(L, "net.quic_max_streams must be within <1, 4096>"); + + the_network->quic_params->max_streams = (uint16_t)v; + lua_pushboolean(L, true); + return 1; +} + +static int net_quic_reqire_retry(lua_State *L) +{ + if (kr_fails_assert(the_network)) { + return 0; + } + + // /* Only return current require_retry. */ + if (lua_gettop(L) == 0) { + if (!the_network->quic_params) { + return 0; + } + + lua_newtable(L); + lua_pushboolean(L, the_network->quic_params->require_retry); + return 1; + } + + if (lua_gettop(L) != 1 || !lua_isboolean(L, 1)) + lua_error_p(L, "net.quic_require_retry requires one boolean value"); + + bool v = lua_toboolean(L, 1); + + /* Allocate struct if needed */ + if (!the_network->quic_params && quic_configuration_set() != kr_ok()) { + lua_error_p(L, "Out of memory allocating net_quic_params"); + } + + the_network->quic_params->require_retry = v; + lua_pushboolean(L, true); + return 1; +} + + /** Return a lua table with TLS authentication parameters. * The format is the same as passed to policy.TLS_FORWARD(); * more precisely, it's in a compatible canonical form. */ @@ -1243,6 +1345,9 @@ int kr_bindings_net(lua_State *L) { "tls_padding", net_tls_padding }, { "tls_sticket_secret", net_tls_sticket_secret_string }, { "tls_sticket_secret_file", net_tls_sticket_secret_file }, + { "quic_max_conns", net_quic_max_conns }, + { "quic_max_streams", net_quic_max_streams }, + { "quic_require_retry", net_quic_reqire_retry }, { "outgoing_v4", net_outgoing_v4 }, { "outgoing_v6", net_outgoing_v6 }, { "tcp_in_idle", net_tcp_in_idle }, diff --git a/daemon/lua/kres-gen-33.lua b/daemon/lua/kres-gen-33.lua index e999b89c3..54f01bb67 100644 --- a/daemon/lua/kres-gen-33.lua +++ b/daemon/lua/kres-gen-33.lua @@ -555,7 +555,7 @@ typedef struct { _Bool tls; _Bool http; _Bool xdp; - _Bool doq; + _Bool quic; _Bool freebind; const char *kind; } endpoint_flags_t; @@ -631,6 +631,7 @@ struct network { } listen_tcp_buflens; _Bool enable_connect_udp; uint16_t min_udp_source_port; + struct net_quic_params *quic_params; }; struct args *the_args; struct endpoint { diff --git a/daemon/network.c b/daemon/network.c index dd5fa3073..18b1159b7 100644 --- a/daemon/network.c +++ b/daemon/network.c @@ -8,6 +8,7 @@ #include "daemon/bindings/impl.h" #include "daemon/io.h" #include "daemon/tls.h" +#include "daemon/quic_common.h" #include "daemon/worker.h" #include "lib/utils.h" @@ -80,6 +81,7 @@ void network_init(uv_loop_t *loop, int tcp_backlog) the_network->tcp_backlog = tcp_backlog; the_network->enable_connect_udp = true; the_network->min_udp_source_port = 1024; + the_network->quic_params = NULL; // On Linux, unset means some auto-tuning mechanism also depending on RAM, // which might be OK default (together with the user_timeout above) @@ -310,6 +312,7 @@ void network_deinit(void) trie_free(the_network->proxy_addrs6); tls_credentials_free(the_network->tls_credentials); + quic_configuration_free(the_network->quic_params); tls_client_params_free(the_network->tls_client_params); tls_session_ticket_ctx_destroy(the_network->tls_session_ticket_ctx); #ifndef NDEBUG diff --git a/daemon/network.h b/daemon/network.h index 39f5b7f76..6f2106811 100644 --- a/daemon/network.h +++ b/daemon/network.h @@ -70,6 +70,12 @@ struct net_proxy_data { uint8_t netmask; /**< Number of bits to be matched */ }; +struct net_quic_params { + uint16_t max_conns; + uint16_t max_streams; + bool require_retry; +}; + struct network { uv_loop_t *loop; @@ -116,6 +122,8 @@ struct network { /** Low source port (e.g. 53) might be useful for attacks with spoofed source IPs. */ uint16_t min_udp_source_port; + + struct net_quic_params *quic_params; }; /** Pointer to the singleton network state. NULL if not initialized. */ diff --git a/daemon/quic_common.c b/daemon/quic_common.c index 7ba462c75..23f273887 100644 --- a/daemon/quic_common.c +++ b/daemon/quic_common.c @@ -3,10 +3,46 @@ */ #include #include "contrib/openbsd/siphash.h" -#include "quic_common.h" #include "libdnssec/random.h" -#include "session2.h" + +#include "quic_common.h" #include "quic_conn.h" +#include "session2.h" +#include "network.h" + +int quic_configuration_set(void) +{ + if (kr_fails_assert(the_network)) { + return kr_error(EINVAL); + } + + if (the_network->quic_params) { + return kr_ok(); + } + + struct net_quic_params *quic_params = calloc(1, sizeof(*quic_params)); + if (quic_params == NULL) { + return kr_error(ENOMEM); + } + + the_network->quic_params = quic_params; + /* Default values */ + the_network->quic_params->require_retry = false; + the_network->quic_params->max_streams = 1024; + the_network->quic_params->max_conns = 1024; + return kr_ok(); +} + +int quic_configuration_free(struct net_quic_params *quic_params) +{ + if (quic_params == NULL){ + return kr_ok(); + } + + free(quic_params); + + return kr_ok(); +} uint64_t quic_timestamp(void) { diff --git a/daemon/quic_common.h b/daemon/quic_common.h index 674247716..675ec60f9 100644 --- a/daemon/quic_common.h +++ b/daemon/quic_common.h @@ -13,6 +13,7 @@ #include #include "session2.h" +#include "network.h" /** RFC 9250 4.3 DoQ Error Codes for use as application protocol error codes */ typedef enum { @@ -48,12 +49,6 @@ typedef enum { #define BUCKETS_PER_CONNS 8 -/* Application is responsible for extending the stream limit. - * This mainly means that this value limits the number of concurrent streams - * because only once a stream is closed is this max_streams frame sent to the - * remote endpoint. */ -#define MAX_STREAMS_BIDI 1024 - #define MAX_QUIC_PKT_SIZE 65536 #define MAX_QUIC_FRAME_SIZE 65536 #define QUIC_MAX_SEND_PER_RECV 4 @@ -110,6 +105,8 @@ struct kr_quic_stream_param { struct comm_info comm_storage; }; +int quic_configuration_set(void); +int quic_configuration_free(struct net_quic_params *quic_params); bool kr_quic_conn_timeout(struct pl_quic_conn_sess_data *conn, uint64_t *now); uint64_t cid2hash(const ngtcp2_cid *cid, kr_quic_table_t *table); bool init_unique_cid(ngtcp2_cid *cid, size_t len, kr_quic_table_t *table); diff --git a/daemon/quic_conn.c b/daemon/quic_conn.c index b7db39508..9f0fab2f5 100644 --- a/daemon/quic_conn.c +++ b/daemon/quic_conn.c @@ -3,6 +3,7 @@ */ #include "quic_conn.h" +#include "network.h" #include "quic_common.h" #include "quic_stream.h" #include "libdnssec/random.h" @@ -327,7 +328,12 @@ static int conn_new_handler(ngtcp2_conn **pconn, const ngtcp2_path *path, /* We have no use for unidirectional streams */ params.initial_max_streams_uni = 0; - params.initial_max_streams_bidi = MAX_STREAMS_BIDI; + + if (unlikely(kr_fails_assert(the_network && the_network->quic_params))) { + kr_log_debug(DOQ, "Missing network struct or network quic_parameters\n"); + return kr_error(EINVAL); + } + params.initial_max_streams_bidi = the_network->quic_params->max_streams; params.initial_max_stream_data_bidi_local = MAX_QUIC_FRAME_SIZE; params.initial_max_stream_data_bidi_remote = MAX_QUIC_FRAME_SIZE; params.initial_max_data = MAX_QUIC_PKT_SIZE; diff --git a/daemon/quic_conn.h b/daemon/quic_conn.h index 38597221d..1fd3873ea 100644 --- a/daemon/quic_conn.h +++ b/daemon/quic_conn.h @@ -12,8 +12,6 @@ #include "quic_common.h" #include "daemon/tls.h" -#define QUIC_MAX_OPEN_CONNS 1024 - /** QUIC parameters. */ typedef struct { /*! Use QUIC indicator. */ diff --git a/daemon/quic_demux.c b/daemon/quic_demux.c index 2d79dd49f..e5b8348fb 100644 --- a/daemon/quic_demux.c +++ b/daemon/quic_demux.c @@ -7,11 +7,11 @@ #include "quic_conn.h" #include "quic_demux.h" #include "libdnssec/random.h" +#include /* Toggle sending retry for new connections. This is a way to validate the * client address, but it adds 1 round trip to the connection establishment * potentially hindering performance */ -#define DOQ_REQUIRE_RETRY false #define BUCKETS_PER_CONNS 8 // Each connecion has several dCIDs, and each CID takes one hash table bucket. void kr_quic_table_rem(struct pl_quic_conn_sess_data *conn, kr_quic_table_t *table); @@ -198,12 +198,14 @@ void kr_quic_table_sweep(struct kr_quic_table *table, int ret = ngtcp2_conn_handle_expiry(c->conn, now); if (ret != NGTCP2_NO_ERROR) { quic_doq_error_t doq_error = DOQ_NO_ERROR; - send_special(&c->dec_cids, c->table_ref, - ctx, QUIC_SEND_CONN_CLOSE, - c, c->h.session, &doq_error); + /* see https://nghttp2.org/ngtcp2/ngtcp2_conn_handle_expiry.html */ + if (ret != NGTCP2_ERR_IDLE_CLOSE) { + send_special(&c->dec_cids, c->table_ref, + ctx, QUIC_SEND_CONN_CLOSE, + c, c->h.session, &doq_error); + } session2_event(c->h.session->transport.parent, - PROTOLAYER_EVENT_DISCONNECT, - c); + PROTOLAYER_EVENT_DISCONNECT, c); } else { // quic_conn_mark_used(c, table); } @@ -279,8 +281,8 @@ static enum protolayer_iter_cb_result pl_quic_demux_unwrap(void *sess_data, return protolayer_break(ctx, kr_ok()); } - /* additional RTT seems quite expensive for all new connections */ - if (header.tokenlen == 0 && DOQ_REQUIRE_RETRY) { + if (header.tokenlen == 0 && the_network->quic_params + && the_network->quic_params->require_retry) { if (send_special(&dec_cids, demux->conn_table, ctx, QUIC_SEND_RETRY, NULL, demux->h.session, NULL) != kr_ok()) { @@ -458,10 +460,20 @@ static int pl_quic_demux_sess_init(struct session2 *session, void *sess_data, vo struct tls_credentials *creds = the_network->tls_credentials; + /* kresd process was run without a manager and no quic configuration + * which would set defaults was provided -> init and set defaults */ + if (!the_network->quic_params) { + int ret = 0; + if ((ret = quic_configuration_set()) != kr_ok()) { + kr_log_error(DOQ, "Failed to allocate quic defaults\n"); + return ret; + } + } + if (!quic->conn_table) { - quic->conn_table = kr_quic_table_new(QUIC_MAX_OPEN_CONNS, + quic->conn_table = kr_quic_table_new( + the_network->quic_params->max_conns, NGTCP2_MAX_UDP_PAYLOAD_SIZE, creds); - if (!quic->conn_table) { kr_log_error(DOQ, "Failed to create QUIC connection table\n"); return kr_error(ENOMEM); diff --git a/daemon/quic_stream.h b/daemon/quic_stream.h index 9920271b3..33808d9b0 100644 --- a/daemon/quic_stream.h +++ b/daemon/quic_stream.h @@ -9,8 +9,6 @@ #include "quic_conn.h" #include "session2.h" -#define QUIC_MAX_SEND_PER_RECV 4 - struct kr_quic_obuf { struct node node; size_t len; diff --git a/doc/_static/config.schema.json b/doc/_static/config.schema.json index aa58df77c..70786d74b 100644 --- a/doc/_static/config.schema.json +++ b/doc/_static/config.schema.json @@ -249,7 +249,7 @@ "default": null }, "tls": { - "description": "TLS configuration, also affects DNS over TLS and DNS over HTTPS.", + "description": "TLS configuration, also affects DNS over TLS, DNS over HTTPS and DNS over QUIC.", "type": "object", "properties": { "watchdog": { @@ -324,6 +324,36 @@ "padding": true } }, + "quic": { + "description": "DNS over QUIC configuration.", + "type": "object", + "properties": { + "max-conns": { + "type": "integer", + "minimum": 1, + "maximum": 4096, + "description": "Maximum number of active connections a single worker is allowed to accept.", + "default": 1024 + }, + "max-streams": { + "type": "integer", + "minimum": 1, + "maximum": 4096, + "description": "Maximum number of concurrent streams a connection is allowed to open.", + "default": 1024 + }, + "require-retry": { + "type": "boolean", + "description": "Require address validation for unknown source addresses. Adds a 1-RTT delay to connection establishment.", + "default": false + } + }, + "default": { + "max_conns": 1024, + "max_streams": 1024, + "require_retry": false + } + }, "proxy-protocol": { "description": "PROXYv2 protocol configuration.", "type": "object", @@ -483,6 +513,11 @@ "sticket_secret_file": null, "padding": true }, + "quic": { + "max_conns": 1024, + "max_streams": 1024, + "require_retry": false + }, "proxy_protocol": { "enable": false, "allow": null @@ -1577,7 +1612,9 @@ "exterr", "rules", "prlayr", - "defer" + "defer", + "doq", + "ngtcp2" ] }, "description": "List of groups for which 'debug' logging level is set.", diff --git a/doc/user/config-network-server-tls.rst b/doc/user/config-network-server-tls.rst index 34cf9c9e3..143a0d9ff 100644 --- a/doc/user/config-network-server-tls.rst +++ b/doc/user/config-network-server-tls.rst @@ -3,7 +3,7 @@ .. _config-network-server-tls: DoT, DoH and DoQ (encrypted DNS) ---------------------------- +-------------------------------- .. warning:: @@ -13,7 +13,7 @@ DoT, DoH and DoQ (encrypted DNS) See `slides `_ or `the article itself `_. -DoT and DoH encrypt DNS traffic with Transport Layer Security (TLS) protocol +DoT, DoH and DoQ encrypt DNS traffic with Transport Layer Security (TLS) protocol and thus protects DNS traffic from certain types of attacks. You can learn more about DoT and DoH and their implementation in Knot Resolver @@ -90,7 +90,7 @@ the following status codes: .. _dot-doh-doq-config-options: Configuration options for DoT, DoH and DoQ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. note:: @@ -210,11 +210,46 @@ policies. .. _dns-over-quic: DNS-over-QUIC (DoQ) -^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^ + .. note:: - Forwarding over QUIC is not currently supported. + DoQ is currently considered an experimental feature. If you encounter any + issues or have any questions, please do not hesitate to contact us via the + standard communication channels. + DNS-over-QUIC server (:rfc:`9250`) can be configured using ``doq`` kind in :option:`network/listen >`. For certificate configuration, refer to :ref:`dot-doh-doq-config-options`. + +.. option:: network/quic: + + .. option:: max_conns: <1-4096> + + :default: 1024 + + The maximum number of active connections a worker is permitted to accept. + Setting this value too low or too high may negatively affect performance. + Changing this value requires a worker restart. + + .. option:: max_streams: <1-4096> + + :default: 1024 + + The maximum number of concurrent streams a connection can open. + Setting this value too low or too high may negatively affect performance. + Changing this value requires a worker restart. + + .. option:: require_retry: true|false + + :default: false + + Require address validation from unknown addresses. Retry requests might + be sent under certain conditions regardless of this setting. + Note that enabling this option imposes a 1-RTT delay for verifying + the return routability of the source address of a client. + + For further details see: + https://datatracker.ietf.org/doc/html/rfc9000#name-address-validation-using-re + and https://datatracker.ietf.org/doc/html/rfc9250#name-address-validation diff --git a/doc/user/config-network-server.rst b/doc/user/config-network-server.rst index 71d164583..a3b5a9bf7 100644 --- a/doc/user/config-network-server.rst +++ b/doc/user/config-network-server.rst @@ -55,7 +55,7 @@ address + port combination. Port number to listen on. - .. option:: kind: dns|xdp|dot|doh2|doh-legacy + .. option:: kind: dns|xdp|dot|doh2|doh-legacy|doq :default: dns diff --git a/lib/log.c b/lib/log.c index 38c62f29b..0ad699263 100644 --- a/lib/log.c +++ b/lib/log.c @@ -81,9 +81,9 @@ const log_group_names_t log_group_names[] = { GRP_NAME_ITEM(LOG_GRP_RULES), GRP_NAME_ITEM(LOG_GRP_PROTOLAYER), GRP_NAME_ITEM(LOG_GRP_DEFER), - GRP_NAME_ITEM(LOG_GRP_REQDBG), GRP_NAME_ITEM(LOG_GRP_DOQ), GRP_NAME_ITEM(LOG_GRP_DOQ_LIBNGTCP2), + GRP_NAME_ITEM(LOG_GRP_REQDBG), { NULL, LOG_GRP_UNKNOWN }, }; static_assert(LOG_GRP_REQDBG <= 8 * sizeof(kr_log_groups), "Too many log groups."); diff --git a/python/knot_resolver/datamodel/logging_schema.py b/python/knot_resolver/datamodel/logging_schema.py index d97a5694a..61fbd1f4c 100644 --- a/python/knot_resolver/datamodel/logging_schema.py +++ b/python/knot_resolver/datamodel/logging_schema.py @@ -71,6 +71,8 @@ LogGroupsKresdEnum = Literal[ "rules", "prlayr", "defer", + "doq", + "ngtcp2", # "reqdbg",... (non-displayed section of the enum) ] diff --git a/python/knot_resolver/datamodel/network_schema.py b/python/knot_resolver/datamodel/network_schema.py index 662cd9d28..d6712f287 100644 --- a/python/knot_resolver/datamodel/network_schema.py +++ b/python/knot_resolver/datamodel/network_schema.py @@ -4,6 +4,7 @@ from knot_resolver.constants import WATCHDOG_LIB from knot_resolver.datamodel.types import ( EscapedStr32B, Int0_512, + Int1_4096, Int0_65535, InterfaceOptionalPort, IPAddress, @@ -48,6 +49,27 @@ class AddressRenumberingSchema(ConfigSchema): destination: Union[IPAddressEM, IPAddress] +class QUICSchema(ConfigSchema): + class Raw(ConfigSchema): + """ + Optional DoQ configuration + + --- + max_conns: Maximum number of active connections a single worker is allowed to accept. + max_streams: Maximum number of concurrent streams a connection is allowed to open. + require_retry: Require address validation for unknown source addresses. Adds a 1-RTT delay to connection establishment. + """ + + max_conns: Int1_4096 = Int1_4096(1024) + max_streams: Int1_4096 = Int1_4096(1024) + require_retry: bool = False; + + _LAYER = Raw + + max_conns: Int1_4096 = Int1_4096(1024) + max_streams: Int1_4096 = Int1_4096(1024) + require_retry: bool = False; + class TLSSchema(ConfigSchema): class Raw(ConfigSchema): """ @@ -182,7 +204,8 @@ class NetworkSchema(ConfigSchema): edns_tcp_keepalive: Allows clients to discover the connection timeout. (RFC 7828) edns_buffer_size: Maximum EDNS payload size advertised in DNS packets. Different values can be configured for communication downstream (towards clients) and upstream (towards other DNS servers). address_renumbering: Renumbers addresses in answers to different address space. - tls: TLS configuration, also affects DNS over TLS and DNS over HTTPS. + tls: TLS configuration, also affects DNS over TLS, DNS over HTTPS and DNS over QUIC. + quic: DNS over QUIC configuration. proxy_protocol: PROXYv2 protocol configuration. listen: List of interfaces to listen to and its configuration. """ @@ -197,6 +220,7 @@ class NetworkSchema(ConfigSchema): address_renumbering: Optional[List[AddressRenumberingSchema]] = None tls: TLSSchema = TLSSchema() proxy_protocol: ProxyProtocolSchema = ProxyProtocolSchema() + quic: QUICSchema = QUICSchema() listen: List[ListenSchema] = [ ListenSchema({"interface": "127.0.0.1"}), ListenSchema({"interface": "::1", "freebind": True}), diff --git a/python/knot_resolver/datamodel/templates/network.lua.j2 b/python/knot_resolver/datamodel/templates/network.lua.j2 index 81ec14595..aee006061 100644 --- a/python/knot_resolver/datamodel/templates/network.lua.j2 +++ b/python/knot_resolver/datamodel/templates/network.lua.j2 @@ -57,6 +57,25 @@ false {%- endif -%} ) +-- network.quic.max_conns +{% if cfg.network.quic.max_conns %} +net.quic_max_conns({{ cfg.network.quic.max_conns }}) +{% endif %} + +-- network.quic.max_streams +{% if cfg.network.quic.max_streams %} +net.quic_max_streams({{ cfg.network.quic.max_streams }}) +{% endif %} + +-- network.quic.require_retry +net.quic_require_retry( +{%- if cfg.network.quic.require_retry == true -%} +true +{%- else -%} +false +{%- endif -%} +) + {% if cfg.network.address_renumbering %} -- network.address-renumbering modules.load('renumber') diff --git a/python/knot_resolver/datamodel/types/__init__.py b/python/knot_resolver/datamodel/types/__init__.py index 7e5cab417..bf6439c97 100644 --- a/python/knot_resolver/datamodel/types/__init__.py +++ b/python/knot_resolver/datamodel/types/__init__.py @@ -9,6 +9,7 @@ from .types import ( IDPattern, Int0_32, Int0_512, + Int1_4096, Int0_65535, InterfaceName, InterfaceOptionalPort, @@ -42,6 +43,7 @@ __all__ = [ "IDPattern", "Int0_32", "Int0_512", + "Int1_4096", "Int0_65535", "InterfaceName", "InterfaceOptionalPort", diff --git a/python/knot_resolver/datamodel/types/types.py b/python/knot_resolver/datamodel/types/types.py index fb22169ef..9ade24816 100644 --- a/python/knot_resolver/datamodel/types/types.py +++ b/python/knot_resolver/datamodel/types/types.py @@ -31,6 +31,11 @@ class Int0_512(IntRangeBase): # noqa: N801 _max: int = 512 +class Int1_4096(IntRangeBase): # noqa: N801 + _min: int = 1 + _max: int = 4096 + + class Int0_65535(IntRangeBase): # noqa: N801 _min: int = 0 _max: int = 65_535 diff --git a/tests/manager/datamodel/test_network_schema.py b/tests/manager/datamodel/test_network_schema.py index 1204e0115..3723fbdb1 100644 --- a/tests/manager/datamodel/test_network_schema.py +++ b/tests/manager/datamodel/test_network_schema.py @@ -33,6 +33,7 @@ def test_listen_defaults(): ({"interface": ["::1"], "kind": "dot"}, 853), ({"interface": ["::1"], "kind": "doh-legacy"}, 443), ({"interface": ["::1"], "kind": "doh2"}, 443), + ({"interface": ["::1"], "kind": "doq"}, 853), ], ) def test_listen_port_defaults(listen: Dict[str, Any], port: Optional[int]):