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