1169689Skan/*	$NetBSD: server.c,v 1.9 2024/02/21 22:52:46 christos Exp $	*/
2169689Skan
3169689Skan/*
4169689Skan * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5169689Skan *
6169689Skan * SPDX-License-Identifier: MPL-2.0
7169689Skan *
8169689Skan * This Source Code Form is subject to the terms of the Mozilla Public
9169689Skan * License, v. 2.0. If a copy of the MPL was not distributed with this
10169689Skan * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11169689Skan *
12169689Skan * See the COPYRIGHT file distributed with this work for additional
13169689Skan * information regarding copyright ownership.
14169689Skan */
15169689Skan
16169689Skan/*! \file */
17169689Skan
18169689Skan#include <stdbool.h>
19169689Skan
20169689Skan#include <isc/mem.h>
21169689Skan#include <isc/stats.h>
22169689Skan#include <isc/util.h>
23169689Skan
24169689Skan#include <dns/stats.h>
25169689Skan#include <dns/tkey.h>
26169689Skan
27169689Skan#include <ns/query.h>
28169689Skan#include <ns/server.h>
29169689Skan#include <ns/stats.h>
30169689Skan
31169689Skan#define SCTX_MAGIC    ISC_MAGIC('S', 'c', 't', 'x')
32169689Skan#define SCTX_VALID(s) ISC_MAGIC_VALID(s, SCTX_MAGIC)
33169689Skan
34169689Skan#define CHECKFATAL(op)                                  \
35169689Skan	do {                                            \
36169689Skan		result = (op);                          \
37169689Skan		RUNTIME_CHECK(result == ISC_R_SUCCESS); \
38	} while (0)
39
40isc_result_t
41ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview,
42		 ns_server_t **sctxp) {
43	ns_server_t *sctx;
44	isc_result_t result;
45
46	REQUIRE(sctxp != NULL && *sctxp == NULL);
47
48	sctx = isc_mem_get(mctx, sizeof(*sctx));
49
50	memset(sctx, 0, sizeof(*sctx));
51
52	isc_mem_attach(mctx, &sctx->mctx);
53
54	/*
55	 * See here for more details:
56	 * https://github.com/jemalloc/jemalloc/issues/2483
57	 */
58
59	isc_refcount_init(&sctx->references, 1);
60
61	isc_quota_init(&sctx->xfroutquota, 10);
62	isc_quota_init(&sctx->tcpquota, 10);
63	isc_quota_init(&sctx->recursionquota, 100);
64	isc_quota_init(&sctx->updquota, 100);
65	ISC_LIST_INIT(sctx->http_quotas);
66	isc_mutex_init(&sctx->http_quotas_lock);
67
68	CHECKFATAL(dns_tkeyctx_create(mctx, &sctx->tkeyctx));
69
70	CHECKFATAL(ns_stats_create(mctx, ns_statscounter_max, &sctx->nsstats));
71
72	CHECKFATAL(dns_rdatatypestats_create(mctx, &sctx->rcvquerystats));
73
74	CHECKFATAL(dns_opcodestats_create(mctx, &sctx->opcodestats));
75
76	CHECKFATAL(dns_rcodestats_create(mctx, &sctx->rcodestats));
77
78	CHECKFATAL(isc_stats_create(mctx, &sctx->udpinstats4,
79				    dns_sizecounter_in_max));
80
81	CHECKFATAL(isc_stats_create(mctx, &sctx->udpoutstats4,
82				    dns_sizecounter_out_max));
83
84	CHECKFATAL(isc_stats_create(mctx, &sctx->udpinstats6,
85				    dns_sizecounter_in_max));
86
87	CHECKFATAL(isc_stats_create(mctx, &sctx->udpoutstats6,
88				    dns_sizecounter_out_max));
89
90	CHECKFATAL(isc_stats_create(mctx, &sctx->tcpinstats4,
91				    dns_sizecounter_in_max));
92
93	CHECKFATAL(isc_stats_create(mctx, &sctx->tcpoutstats4,
94				    dns_sizecounter_out_max));
95
96	CHECKFATAL(isc_stats_create(mctx, &sctx->tcpinstats6,
97				    dns_sizecounter_in_max));
98
99	CHECKFATAL(isc_stats_create(mctx, &sctx->tcpoutstats6,
100				    dns_sizecounter_out_max));
101
102	sctx->udpsize = 1232;
103	sctx->transfer_tcp_message_size = 20480;
104
105	sctx->fuzztype = isc_fuzz_none;
106	sctx->fuzznotify = NULL;
107
108	sctx->matchingview = matchingview;
109	sctx->answercookie = true;
110
111	ISC_LIST_INIT(sctx->altsecrets);
112
113	sctx->magic = SCTX_MAGIC;
114	*sctxp = sctx;
115
116	return (ISC_R_SUCCESS);
117}
118
119void
120ns_server_attach(ns_server_t *src, ns_server_t **dest) {
121	REQUIRE(SCTX_VALID(src));
122	REQUIRE(dest != NULL && *dest == NULL);
123
124	isc_refcount_increment(&src->references);
125
126	*dest = src;
127}
128
129void
130ns_server_detach(ns_server_t **sctxp) {
131	ns_server_t *sctx;
132
133	REQUIRE(sctxp != NULL && SCTX_VALID(*sctxp));
134	sctx = *sctxp;
135	*sctxp = NULL;
136
137	if (isc_refcount_decrement(&sctx->references) == 1) {
138		ns_altsecret_t *altsecret;
139		isc_quota_t *http_quota;
140
141		while ((altsecret = ISC_LIST_HEAD(sctx->altsecrets)) != NULL) {
142			ISC_LIST_UNLINK(sctx->altsecrets, altsecret, link);
143			isc_mem_put(sctx->mctx, altsecret, sizeof(*altsecret));
144		}
145
146		isc_quota_destroy(&sctx->updquota);
147		isc_quota_destroy(&sctx->recursionquota);
148		isc_quota_destroy(&sctx->tcpquota);
149		isc_quota_destroy(&sctx->xfroutquota);
150
151		http_quota = ISC_LIST_HEAD(sctx->http_quotas);
152		while (http_quota != NULL) {
153			isc_quota_t *next = NULL;
154
155			next = ISC_LIST_NEXT(http_quota, link);
156			ISC_LIST_DEQUEUE(sctx->http_quotas, http_quota, link);
157			isc_quota_destroy(http_quota);
158			isc_mem_put(sctx->mctx, http_quota,
159				    sizeof(*http_quota));
160			http_quota = next;
161		}
162		isc_mutex_destroy(&sctx->http_quotas_lock);
163
164		if (sctx->server_id != NULL) {
165			isc_mem_free(sctx->mctx, sctx->server_id);
166		}
167
168		if (sctx->blackholeacl != NULL) {
169			dns_acl_detach(&sctx->blackholeacl);
170		}
171		if (sctx->keepresporder != NULL) {
172			dns_acl_detach(&sctx->keepresporder);
173		}
174		if (sctx->tkeyctx != NULL) {
175			dns_tkeyctx_destroy(&sctx->tkeyctx);
176		}
177
178		if (sctx->nsstats != NULL) {
179			ns_stats_detach(&sctx->nsstats);
180		}
181
182		if (sctx->rcvquerystats != NULL) {
183			dns_stats_detach(&sctx->rcvquerystats);
184		}
185		if (sctx->opcodestats != NULL) {
186			dns_stats_detach(&sctx->opcodestats);
187		}
188		if (sctx->rcodestats != NULL) {
189			dns_stats_detach(&sctx->rcodestats);
190		}
191
192		if (sctx->udpinstats4 != NULL) {
193			isc_stats_detach(&sctx->udpinstats4);
194		}
195		if (sctx->tcpinstats4 != NULL) {
196			isc_stats_detach(&sctx->tcpinstats4);
197		}
198		if (sctx->udpoutstats4 != NULL) {
199			isc_stats_detach(&sctx->udpoutstats4);
200		}
201		if (sctx->tcpoutstats4 != NULL) {
202			isc_stats_detach(&sctx->tcpoutstats4);
203		}
204
205		if (sctx->udpinstats6 != NULL) {
206			isc_stats_detach(&sctx->udpinstats6);
207		}
208		if (sctx->tcpinstats6 != NULL) {
209			isc_stats_detach(&sctx->tcpinstats6);
210		}
211		if (sctx->udpoutstats6 != NULL) {
212			isc_stats_detach(&sctx->udpoutstats6);
213		}
214		if (sctx->tcpoutstats6 != NULL) {
215			isc_stats_detach(&sctx->tcpoutstats6);
216		}
217
218		sctx->magic = 0;
219
220		isc_mem_putanddetach(&sctx->mctx, sctx, sizeof(*sctx));
221	}
222}
223
224isc_result_t
225ns_server_setserverid(ns_server_t *sctx, const char *serverid) {
226	REQUIRE(SCTX_VALID(sctx));
227
228	if (sctx->server_id != NULL) {
229		isc_mem_free(sctx->mctx, sctx->server_id);
230		sctx->server_id = NULL;
231	}
232
233	if (serverid != NULL) {
234		sctx->server_id = isc_mem_strdup(sctx->mctx, serverid);
235	}
236
237	return (ISC_R_SUCCESS);
238}
239
240void
241ns_server_setoption(ns_server_t *sctx, unsigned int option, bool value) {
242	REQUIRE(SCTX_VALID(sctx));
243	if (value) {
244		sctx->options |= option;
245	} else {
246		sctx->options &= ~option;
247	}
248}
249
250bool
251ns_server_getoption(ns_server_t *sctx, unsigned int option) {
252	REQUIRE(SCTX_VALID(sctx));
253
254	return ((sctx->options & option) != 0);
255}
256
257void
258ns_server_append_http_quota(ns_server_t *sctx, isc_quota_t *http_quota) {
259	REQUIRE(SCTX_VALID(sctx));
260	REQUIRE(http_quota != NULL);
261
262	LOCK(&sctx->http_quotas_lock);
263	ISC_LINK_INIT(http_quota, link);
264	ISC_LIST_APPEND(sctx->http_quotas, http_quota, link);
265	UNLOCK(&sctx->http_quotas_lock);
266}
267