233 lines
4.8 KiB
C++
233 lines
4.8 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1998, Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
range.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements an efficient mapping from an arbitrary range of
|
|||
|
IP addresses to a minimal set of IP address-mask pairs covering the range.
|
|||
|
|
|||
|
The key to the approach is to regard the set of all possible IP addresses
|
|||
|
as a full 32-bit deep binary tree. Then a single IP address is a path
|
|||
|
through that tree, and a range of addresses is the area between two paths
|
|||
|
through the tree. We then describe such a path-delineated area by pruning
|
|||
|
full subtrees of the area recursively from left to right.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Abolade Gbadegesin (aboladeg) 20-Mar-1998
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
DecomposeRange(
|
|||
|
ULONG StartAddress,
|
|||
|
ULONG EndAddress,
|
|||
|
ULONG Mask,
|
|||
|
PDECOMPOSE_RANGE_CALLBACK Callback,
|
|||
|
PVOID CallbackContext
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine decomposes the range StartAddress-EndAddress into
|
|||
|
a minimal set of address-mask pairs, passing the generated
|
|||
|
pairs to the given callback routine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
StartAddress - the start of the range
|
|||
|
|
|||
|
EndAddress - the end of the range
|
|||
|
|
|||
|
Mask - the most general mask covering the range
|
|||
|
|
|||
|
Callback - routine invoked for each generated address-mask pair
|
|||
|
|
|||
|
CallbackContext - context passed to 'Callback'.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG temp;
|
|||
|
|
|||
|
//
|
|||
|
// Step 1:
|
|||
|
// Check for the first base case: the root of a full tree.
|
|||
|
//
|
|||
|
|
|||
|
if ((StartAddress & ~Mask) == 0 && (EndAddress & ~Mask) == ~Mask) {
|
|||
|
|
|||
|
if (Callback) { Callback(StartAddress, Mask, CallbackContext); }
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Step 2.
|
|||
|
// Extend the mask by one bit to cover the first different position
|
|||
|
// between the start and end address, essentially moving down in the tree
|
|||
|
// to the node where the paths branch.
|
|||
|
//
|
|||
|
// . <- Most general mask
|
|||
|
// |
|
|||
|
// * <- branching point
|
|||
|
// / \
|
|||
|
//
|
|||
|
|
|||
|
Mask = ntohl(Mask);
|
|||
|
Mask >>= 1; Mask |= (1<<31);
|
|||
|
Mask = htonl(Mask);
|
|||
|
|
|||
|
//
|
|||
|
// Step 3.
|
|||
|
// Split the range, with the new right edge being a fully-rightward path
|
|||
|
// (no left turns) starting below and to the left of the branching point.
|
|||
|
//
|
|||
|
// . <- branching point
|
|||
|
// / \
|
|||
|
// *
|
|||
|
// \ <- new right edge
|
|||
|
//
|
|||
|
|
|||
|
temp = StartAddress | ~Mask;
|
|||
|
|
|||
|
//
|
|||
|
// Step 4.
|
|||
|
// Check for the second base case:
|
|||
|
// the left edge is a fully-leftward path (all-zeroes).
|
|||
|
//
|
|||
|
|
|||
|
if ((StartAddress & ~Mask) == 0) {
|
|||
|
|
|||
|
if (Callback) { Callback(StartAddress, Mask, CallbackContext); }
|
|||
|
}
|
|||
|
else {
|
|||
|
|
|||
|
//
|
|||
|
// Not a base case, so take the left branch.
|
|||
|
//
|
|||
|
|
|||
|
DecomposeRange(
|
|||
|
StartAddress,
|
|||
|
temp,
|
|||
|
Mask,
|
|||
|
Callback,
|
|||
|
CallbackContext
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// we may be done, if the right edge is also fully rightward
|
|||
|
//
|
|||
|
|
|||
|
if ((StartAddress | ~Mask) == EndAddress) { return; }
|
|||
|
|
|||
|
//
|
|||
|
// Step 5.
|
|||
|
// Decompose the remaining portion of the range,
|
|||
|
// with the new left edge being the fully-leftward path which starts
|
|||
|
// below and to the right of the original branching point.
|
|||
|
//
|
|||
|
// . <- branching point
|
|||
|
// / \
|
|||
|
// *
|
|||
|
// / <- new left edge
|
|||
|
//
|
|||
|
|
|||
|
temp = EndAddress & Mask;
|
|||
|
|
|||
|
//
|
|||
|
// Step 6.
|
|||
|
// Check for the third base case:
|
|||
|
// the right edge is fully-rightward (all-ones).
|
|||
|
//
|
|||
|
|
|||
|
if (EndAddress == (temp | ~Mask)) {
|
|||
|
|
|||
|
if (Callback) { Callback(EndAddress, Mask, CallbackContext); }
|
|||
|
}
|
|||
|
else {
|
|||
|
|
|||
|
//
|
|||
|
// Not a base case; take the right branch.
|
|||
|
//
|
|||
|
|
|||
|
DecomposeRange(
|
|||
|
temp,
|
|||
|
EndAddress,
|
|||
|
MostGeneralMask(temp, EndAddress),
|
|||
|
Callback,
|
|||
|
CallbackContext
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ULONG
|
|||
|
MostGeneralMask(
|
|||
|
ULONG StartAddress,
|
|||
|
ULONG EndAddress
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine generates the most general mask covering the range
|
|||
|
'StartAddress' - 'EndAddress'.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
StartAddress - beginning of range, in network order
|
|||
|
|
|||
|
EndAddress - end of range, in network order
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ULONG - the most general mask
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG CommonBits, Mask;
|
|||
|
StartAddress = ntohl(StartAddress);
|
|||
|
EndAddress = ntohl(EndAddress);
|
|||
|
|
|||
|
//
|
|||
|
// find the bits common to the start address and end address
|
|||
|
//
|
|||
|
|
|||
|
CommonBits = ~(StartAddress ^ EndAddress);
|
|||
|
|
|||
|
//
|
|||
|
// CommonBits now has a 1 in each position where StartAddress and
|
|||
|
// EndAddress are the same.
|
|||
|
// We want to reduce this to only include the longest contiguous
|
|||
|
// most significant bits
|
|||
|
// e.g. 11101110 becomes 11100000 and 11111101 becomes 11111100
|
|||
|
//
|
|||
|
|
|||
|
for (Mask = 0xffffffff; Mask && ((CommonBits & Mask) != Mask); Mask<<=1) { }
|
|||
|
|
|||
|
return htonl(Mask);
|
|||
|
}
|
|||
|
|
|||
|
|