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