From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- src/VBox/NetworkServices/Dhcpd/IPv4Pool.cpp | 209 ++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 src/VBox/NetworkServices/Dhcpd/IPv4Pool.cpp (limited to 'src/VBox/NetworkServices/Dhcpd/IPv4Pool.cpp') diff --git a/src/VBox/NetworkServices/Dhcpd/IPv4Pool.cpp b/src/VBox/NetworkServices/Dhcpd/IPv4Pool.cpp new file mode 100644 index 00000000..5d1e52a1 --- /dev/null +++ b/src/VBox/NetworkServices/Dhcpd/IPv4Pool.cpp @@ -0,0 +1,209 @@ +/* $Id: IPv4Pool.cpp $ */ +/** @file + * DHCP server - A pool of IPv4 addresses. + */ + +/* + * Copyright (C) 2017-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "DhcpdInternal.h" +#include + +#include "IPv4Pool.h" + + +int IPv4Pool::init(const IPv4Range &aRange) RT_NOEXCEPT +{ + AssertReturn(aRange.isValid(), VERR_INVALID_PARAMETER); + + m_range = aRange; + try + { + m_pool.insert(m_range); + } + catch (std::bad_alloc &) + { + return VERR_NO_MEMORY; + } + return VINF_SUCCESS; +} + + +int IPv4Pool::init(RTNETADDRIPV4 aFirstAddr, RTNETADDRIPV4 aLastAddr) RT_NOEXCEPT +{ + return init(IPv4Range(aFirstAddr, aLastAddr)); +} + + +/** + * Internal worker for inserting a range into the pool of available addresses. + * + * @returns IPRT status code (asserted). + * @param a_Range The range to insert. + */ +int IPv4Pool::i_insert(const IPv4Range &a_Range) RT_NOEXCEPT +{ + /* + * Check preconditions. Asserting because nobody checks the return code. + */ + AssertReturn(m_range.isValid(), VERR_INVALID_STATE); + AssertReturn(a_Range.isValid(), VERR_INVALID_PARAMETER); + AssertReturn(m_range.contains(a_Range), VERR_INVALID_PARAMETER); + + /* + * Check that the incoming range doesn't overlap with existing ranges in the pool. + */ + it_t itHint = m_pool.upper_bound(IPv4Range(a_Range.LastAddr)); /* successor, insertion hint */ +#if 0 /** @todo r=bird: This code is wrong. It has no end() check for starters. Since the method is + * only for internal consumption, I've replaced it with a strict build assertion. */ + if (itHint != m_pool.begin()) + { + it_t prev(itHint); + --prev; + if (a_Range.FirstAddr <= prev->LastAddr) + { + LogRel(("%08x-%08x conflicts with %08x-%08x\n", + a_Range.FirstAddr, a_Range.LastAddr, + prev->FirstAddr, prev->LastAddr)); + return VERR_INVALID_PARAMETER; + } + } +#endif +#ifdef VBOX_STRICT + for (it_t it2 = m_pool.begin(); it2 != m_pool.end(); ++it2) + AssertMsg(it2->LastAddr < a_Range.FirstAddr || it2->FirstAddr > a_Range.LastAddr, + ("%08RX32-%08RX32 conflicts with %08RX32-%08RX32\n", + a_Range.FirstAddr, a_Range.LastAddr, it2->FirstAddr, it2->LastAddr)); +#endif + + /* + * No overlaps, insert it. + */ + try + { + m_pool.insert(itHint, a_Range); + } + catch (std::bad_alloc &) + { + return VERR_NO_MEMORY; + } + return VINF_SUCCESS; +} + + +/** + * Allocates an available IPv4 address from the pool. + * + * @returns Non-zero network order IPv4 address on success, zero address + * (0.0.0.0) on failure. + */ +RTNETADDRIPV4 IPv4Pool::allocate() +{ + RTNETADDRIPV4 RetAddr; + if (!m_pool.empty()) + { + /* Grab the first address in the pool: */ + it_t itBeg = m_pool.begin(); + RetAddr.u = RT_H2N_U32(itBeg->FirstAddr); + + if (itBeg->FirstAddr == itBeg->LastAddr) + m_pool.erase(itBeg); + else + { + /* Trim the entry (re-inserting it): */ + IPv4Range trimmed = *itBeg; + trimmed.FirstAddr += 1; + Assert(trimmed.FirstAddr <= trimmed.LastAddr); + m_pool.erase(itBeg); + try + { + m_pool.insert(trimmed); + } + catch (std::bad_alloc &) + { + /** @todo r=bird: Theortically the insert could fail with a bad_alloc and we'd + * drop a range of IP address. It would be nice if we could safely modify itBit + * without having to re-insert it. The author of this code (not bird) didn't + * seem to think this safe? + * + * If we want to play safe and all that, just use a AVLRU32TREE (or AVLRU64TREE + * if lazy) AVL tree from IPRT. Since we know exactly how it's implemented and + * works, there will be no uncertanties like this when using it (both here + * and in the i_insert validation logic). */ + LogRelFunc(("Caught bad_alloc! We're truely buggered now!\n")); + } + } + } + else + RetAddr.u = 0; + return RetAddr; +} + + +/** + * Allocate the given address. + * + * @returns Success indicator. + * @param a_Addr The IP address to allocate (network order). + */ +bool IPv4Pool::allocate(RTNETADDRIPV4 a_Addr) +{ + /* + * Find the range containing a_Addr. + */ + it_t it = m_pool.lower_bound(IPv4Range(a_Addr)); /* candidate range */ + if (it != m_pool.end()) + { + Assert(RT_N2H_U32(a_Addr.u) <= it->LastAddr); /* by definition of < and lower_bound */ + + if (it->contains(a_Addr)) + { + /* + * Remove a_Addr from the range by way of re-insertion. + */ + const IPV4HADDR haddr = RT_N2H_U32(a_Addr.u); + IPV4HADDR first = it->FirstAddr; + IPV4HADDR last = it->LastAddr; + + m_pool.erase(it); + if (first != last) + { + if (haddr == first) + i_insert(++first, last); + else if (haddr == last) + i_insert(first, --last); + else + { + i_insert(first, haddr - 1); + i_insert(haddr + 1, last); + } + } + + return true; + } + } + return false; +} -- cgit v1.2.3