github.com/noisysockets/noisysockets@v0.21.2-0.20240515114641-7f467e651c90/internal/util/prefix_range.go (about)

     1  // SPDX-License-Identifier: MPL-2.0
     2  /*
     3   * Copyright (C) 2024 The Noisy Sockets Authors.
     4   *
     5   * This Source Code Form is subject to the terms of the Mozilla Public
     6   * License, v. 2.0. If a copy of the MPL was not distributed with this
     7   * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     8   */
     9  
    10  package util
    11  
    12  import (
    13  	"fmt"
    14  	"net/netip"
    15  )
    16  
    17  // PrefixRange takes a netip.Prefix and calculates the starting and ending IP addresses.
    18  func PrefixRange(p netip.Prefix) (startAddr netip.Addr, endAddr netip.Addr, err error) {
    19  	if !p.IsValid() {
    20  		return startAddr, endAddr, fmt.Errorf("invalid prefix")
    21  	}
    22  
    23  	// Check for a valid mask length in case of a IPv4-mapped IPv6 address.
    24  	if p.Addr().Is4In6() && p.Bits() < 96 {
    25  		return startAddr, endAddr, fmt.Errorf("prefix with 4in6 address must have mask >= 96")
    26  	}
    27  
    28  	// Calculate the first address by applying the network mask, which zeroes out the host bits.
    29  	startAddr = p.Masked().Addr()
    30  
    31  	// Adjust mask bits for IPv4 addresses to accommodate the IPv4-mapped IPv6 address.
    32  	maskBits := p.Bits()
    33  	if startAddr.Is4() {
    34  		maskBits += 96
    35  	}
    36  
    37  	// Calculate the last address by setting the host bits of the address.
    38  	as16 := startAddr.As16()
    39  	for b := maskBits; b < 128; b++ {
    40  		byteIndex, bitIndex := b/8, 7-(b%8)
    41  		as16[byteIndex] |= 1 << uint(bitIndex)
    42  	}
    43  
    44  	endAddr = netip.AddrFrom16(as16)
    45  
    46  	// If the prefix is IPv4, unmap from the IPv4-mapped IPv6 address space.
    47  	if startAddr.Is4() {
    48  		endAddr = endAddr.Unmap()
    49  	}
    50  
    51  	return startAddr, endAddr, nil
    52  }