1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7 *
8 * See the COPYRIGHT file distributed with this work for additional
9 * information regarding copyright ownership.
10 */
11
12
13 /*! \file */
14
15 #include <config.h>
16
17 #include <inttypes.h>
18 #include <stdbool.h>
19
20 #include <isc/mem.h>
21 #include <isc/portset.h>
22 #include <isc/string.h>
23 #include <isc/types.h>
24 #include <isc/util.h>
25
26 #define ISC_PORTSET_BUFSIZE (65536 / (sizeof(uint32_t) * 8))
27
28 /*%
29 * Internal representation of portset. It's an array of 32-bit integers, each
30 * bit corresponding to a single port in the ascending order. For example,
31 * the second most significant bit of buf[0] corresponds to port 1.
32 */
33 struct isc_portset {
34 unsigned int nports; /*%< number of ports in the set */
35 uint32_t buf[ISC_PORTSET_BUFSIZE];
36 };
37
38 static inline bool
portset_isset(isc_portset_t * portset,in_port_t port)39 portset_isset(isc_portset_t *portset, in_port_t port) {
40 return (portset->buf[port >> 5] & ((uint32_t)1 << (port & 31)));
41 }
42
43 static inline void
portset_add(isc_portset_t * portset,in_port_t port)44 portset_add(isc_portset_t *portset, in_port_t port) {
45 if (!portset_isset(portset, port)) {
46 portset->nports++;
47 portset->buf[port >> 5] |= ((uint32_t)1 << (port & 31));
48 }
49 }
50
51 static inline void
portset_remove(isc_portset_t * portset,in_port_t port)52 portset_remove(isc_portset_t *portset, in_port_t port) {
53 if (portset_isset(portset, port)) {
54 portset->nports--;
55 portset->buf[port >> 5] &= ~((uint32_t)1 << (port & 31));
56 }
57 }
58
59 isc_result_t
isc_portset_create(isc_mem_t * mctx,isc_portset_t ** portsetp)60 isc_portset_create(isc_mem_t *mctx, isc_portset_t **portsetp) {
61 isc_portset_t *portset;
62
63 REQUIRE(portsetp != NULL && *portsetp == NULL);
64
65 portset = isc_mem_get(mctx, sizeof(*portset));
66 if (portset == NULL)
67 return (ISC_R_NOMEMORY);
68
69 /* Make the set 'empty' by default */
70 memset(portset, 0, sizeof(*portset));
71 *portsetp = portset;
72
73 return (ISC_R_SUCCESS);
74 }
75
76 void
isc_portset_destroy(isc_mem_t * mctx,isc_portset_t ** portsetp)77 isc_portset_destroy(isc_mem_t *mctx, isc_portset_t **portsetp) {
78 isc_portset_t *portset;
79
80 REQUIRE(portsetp != NULL);
81 portset = *portsetp;
82
83 isc_mem_put(mctx, portset, sizeof(*portset));
84 }
85
86 bool
isc_portset_isset(isc_portset_t * portset,in_port_t port)87 isc_portset_isset(isc_portset_t *portset, in_port_t port) {
88 REQUIRE(portset != NULL);
89
90 return (portset_isset(portset, port));
91 }
92
93 unsigned int
isc_portset_nports(isc_portset_t * portset)94 isc_portset_nports(isc_portset_t *portset) {
95 REQUIRE(portset != NULL);
96
97 return (portset->nports);
98 }
99
100 void
isc_portset_add(isc_portset_t * portset,in_port_t port)101 isc_portset_add(isc_portset_t *portset, in_port_t port) {
102 REQUIRE(portset != NULL);
103
104 portset_add(portset, port);
105 }
106
107 void
isc_portset_remove(isc_portset_t * portset,in_port_t port)108 isc_portset_remove(isc_portset_t *portset, in_port_t port) {
109 portset_remove(portset, port);
110 }
111
112 void
isc_portset_addrange(isc_portset_t * portset,in_port_t port_lo,in_port_t port_hi)113 isc_portset_addrange(isc_portset_t *portset, in_port_t port_lo,
114 in_port_t port_hi)
115 {
116 in_port_t p;
117
118 REQUIRE(portset != NULL);
119 REQUIRE(port_lo <= port_hi);
120
121 p = port_lo;
122 do {
123 portset_add(portset, p);
124 } while (p++ < port_hi);
125 }
126
127 void
isc_portset_removerange(isc_portset_t * portset,in_port_t port_lo,in_port_t port_hi)128 isc_portset_removerange(isc_portset_t *portset, in_port_t port_lo,
129 in_port_t port_hi)
130 {
131 in_port_t p;
132
133 REQUIRE(portset != NULL);
134 REQUIRE(port_lo <= port_hi);
135
136 p = port_lo;
137 do {
138 portset_remove(portset, p);
139 } while (p++ < port_hi);
140 }
141