1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * SPDX-License-Identifier: MPL-2.0
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 /*! \file */
15 
16 #include <stdbool.h>
17 
18 #include <isc/mem.h>
19 #include <isc/util.h>
20 
21 #include <dns/acl.h>
22 
23 #include <ns/listenlist.h>
24 
25 static void
26 destroy(ns_listenlist_t *list);
27 
28 isc_result_t
ns_listenelt_create(isc_mem_t * mctx,in_port_t port,isc_dscp_t dscp,dns_acl_t * acl,ns_listenelt_t ** target)29 ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
30 		    dns_acl_t *acl, ns_listenelt_t **target) {
31 	ns_listenelt_t *elt = NULL;
32 	REQUIRE(target != NULL && *target == NULL);
33 	elt = isc_mem_get(mctx, sizeof(*elt));
34 	elt->mctx = mctx;
35 	ISC_LINK_INIT(elt, link);
36 	elt->port = port;
37 	elt->dscp = dscp;
38 	elt->acl = acl;
39 	*target = elt;
40 	return (ISC_R_SUCCESS);
41 }
42 
43 void
ns_listenelt_destroy(ns_listenelt_t * elt)44 ns_listenelt_destroy(ns_listenelt_t *elt) {
45 	if (elt->acl != NULL) {
46 		dns_acl_detach(&elt->acl);
47 	}
48 	isc_mem_put(elt->mctx, elt, sizeof(*elt));
49 }
50 
51 isc_result_t
ns_listenlist_create(isc_mem_t * mctx,ns_listenlist_t ** target)52 ns_listenlist_create(isc_mem_t *mctx, ns_listenlist_t **target) {
53 	ns_listenlist_t *list = NULL;
54 	REQUIRE(target != NULL && *target == NULL);
55 	list = isc_mem_get(mctx, sizeof(*list));
56 	list->mctx = mctx;
57 	list->refcount = 1;
58 	ISC_LIST_INIT(list->elts);
59 	*target = list;
60 	return (ISC_R_SUCCESS);
61 }
62 
63 static void
destroy(ns_listenlist_t * list)64 destroy(ns_listenlist_t *list) {
65 	ns_listenelt_t *elt, *next;
66 	for (elt = ISC_LIST_HEAD(list->elts); elt != NULL; elt = next) {
67 		next = ISC_LIST_NEXT(elt, link);
68 		ns_listenelt_destroy(elt);
69 	}
70 	isc_mem_put(list->mctx, list, sizeof(*list));
71 }
72 
73 void
ns_listenlist_attach(ns_listenlist_t * source,ns_listenlist_t ** target)74 ns_listenlist_attach(ns_listenlist_t *source, ns_listenlist_t **target) {
75 	INSIST(source->refcount > 0);
76 	source->refcount++;
77 	*target = source;
78 }
79 
80 void
ns_listenlist_detach(ns_listenlist_t ** listp)81 ns_listenlist_detach(ns_listenlist_t **listp) {
82 	ns_listenlist_t *list = *listp;
83 	*listp = NULL;
84 	INSIST(list->refcount > 0);
85 	list->refcount--;
86 	if (list->refcount == 0) {
87 		destroy(list);
88 	}
89 }
90 
91 isc_result_t
ns_listenlist_default(isc_mem_t * mctx,in_port_t port,isc_dscp_t dscp,bool enabled,ns_listenlist_t ** target)92 ns_listenlist_default(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
93 		      bool enabled, ns_listenlist_t **target) {
94 	isc_result_t result;
95 	dns_acl_t *acl = NULL;
96 	ns_listenelt_t *elt = NULL;
97 	ns_listenlist_t *list = NULL;
98 
99 	REQUIRE(target != NULL && *target == NULL);
100 	if (enabled) {
101 		result = dns_acl_any(mctx, &acl);
102 	} else {
103 		result = dns_acl_none(mctx, &acl);
104 	}
105 	if (result != ISC_R_SUCCESS) {
106 		goto cleanup;
107 	}
108 
109 	result = ns_listenelt_create(mctx, port, dscp, acl, &elt);
110 	if (result != ISC_R_SUCCESS) {
111 		goto cleanup_acl;
112 	}
113 
114 	result = ns_listenlist_create(mctx, &list);
115 	if (result != ISC_R_SUCCESS) {
116 		goto cleanup_listenelt;
117 	}
118 
119 	ISC_LIST_APPEND(list->elts, elt, link);
120 
121 	*target = list;
122 	return (ISC_R_SUCCESS);
123 
124 cleanup_listenelt:
125 	ns_listenelt_destroy(elt);
126 cleanup_acl:
127 	dns_acl_detach(&acl);
128 cleanup:
129 	return (result);
130 }
131