Algorithm 如何获取不在给定IP地址范围内的所有IP地址
我需要能够输出不在给定IP地址范围列表中的所有IP地址范围 我可以使用某种算法来完成这类任务,并将其转换为工作代码Algorithm 如何获取不在给定IP地址范围内的所有IP地址,algorithm,network-programming,ip,salesforce,apex,Algorithm,Network Programming,Ip,Salesforce,Apex,我需要能够输出不在给定IP地址范围列表中的所有IP地址范围 我可以使用某种算法来完成这类任务,并将其转换为工作代码 基本上,我将使用Salesforce Apex代码,因此,如果给定的示例可行,任何类似JAVA的语言都可以 首先,我假设您的意思是您获得一个或多个不相交的CIDR范围作为输入,并且需要生成所有CIDR范围的列表,其中不包括任何作为输入的CIDR范围。为了方便起见,我们进一步假设输入不包括整个IP地址空间:即0.0.0.0/0。(这可以通过一个单独的特殊情况来解决,但没有多大意义。
- 基本上,我将使用Salesforce Apex代码,因此,如果给定的示例可行,任何类似JAVA的语言都可以
0.0.0.0/0
。(这可以通过一个单独的特殊情况来解决,但没有多大意义。)
我以前也写过类似的代码,虽然我不能随意分享代码,但我可以描述方法。它本质上是一个二进制搜索算法,在这个算法中,你重复地将整个地址空间平分,直到你分离出你感兴趣的一个范围
把IP地址空间想象成一棵二叉树:根上是完整的IPv4地址空间0.0.0/0
。它的子级分别代表地址空间的一半:0.0.0/1
和128.0.0/1。
这些子级又可以细分,分别创建子级0.0.0.0/2
/64.0.0/2
和128.0.0.0/2
/192.0.0.0/2,
。一直这样下去,你会得到2**32
叶子,每个叶子代表一个/32
(即一个地址)
现在,将此树看作是从输入列表中排除的地址空间的一部分。因此,您的任务是遍历这棵树,从树中的输入列表中找到每个范围,并删除输入中树的所有部分,留下地址空间的其余部分
幸运的是,您实际上不需要创建所有的2**32
叶子。如果没有为CIDRN
创建子节点,则可以假定CIDRN+1
及以上位置的每个节点都包含所有节点(您需要一个标志来记住,它已经被细分了,即不再是叶,原因见下文)
因此,首先,整个地址空间都存在于树中,但都可以由单个叶节点表示。调用树excluded,
并用单个节点0.0.0/0对其进行初始化。
现在,考虑第一个输入范围——我们将调用这个代码>试用< /代码>(我将使用<代码> 1427.34.0/ 24 作为初始<代码>试用< /COD>值,只为演示提供一个具体的值)。任务是从
excluded
中删除trial
,留下剩余的地址空间
从current
节点指针设置为excluded
根节点开始
开始:
将试验
CIDR与当前
进行比较。如果是相同的,就完成了(但如果输入范围不相交,并且从输入中排除了0.0.0.0/0
,则永远不会发生这种情况)
否则,如果current
是叶节点(尚未细分,这意味着它表示此CIDR级别及以下的整个地址空间),则设置其sub-divided标志,并为其创建两个子节点:指向其地址空间前半部分的left
指针和指向后半部分的right
指针。适当地标记每个节点(对于根节点的子节点,将是0.0.0.0/1
和128.0.0.0/1
)
确定试验
CIDR是在当前
的左侧还是右侧。对于我们的初始试用值
值,它位于左侧。现在,如果那一侧的指针已经是空的,那么您就完成了(尽管如果您的输入范围不相交,“不可能发生”)
如果trial
CIDR与该侧节点中的CIDR完全相同,则只需释放该节点(以及它可能具有的任何子节点,如果只有不相交的输入,则该子节点也应为无),将指针设置为该侧NULL
,即可完成操作。你刚刚把那片叶子从树上剪下来,把整个范围都排除了
如果试验值与该侧节点中的CIDR不完全相等,则将current
设置到该侧并重新开始(即跳到上面的start标签)
因此,初始输入范围为14.27.34.0/24
,首先将0.0.0/0
分为0.0.0/1
和128.0.0.0/1
。然后从左侧下拉并将0.0.0/1
拆分为0.0.0/2
和64.0.0/2。
然后再次从左侧下拉以创建0.0.0/3
和32.0.0.0/3.
等等,直到23次拆分之后,然后将14.27.34.0/23
拆分为14.27.34.0/24
和14.27.35.0/24。
然后删除左侧14.27.34.0/24
子节点,并将其指针设置为NULL
,保留另一个节点
这将为您留下一个包含24个叶节点的稀疏树(在您删除目标节点之后)。其余叶节点用*标记:
(ROOT)
0.0.0.0/0
/ \
0.0.0.0/1 128.0.0.0/1*
/ \
0.0.0.0/2 64.0.0.0/2*
/ \
0.0.0.0/3 32.0.0.0.0/3*
/ \
0.0.0.0/4 16.0.0.0/4*
/ \
*0.0.0.0/5 8.0.0.0/5
/ \
*8.0.0.0/6 12.0.0.0/6
/ \
*12.0.0.0/7 14.0.0.0/7
/ \
14.0.0.0/8 15.0.0.0/8*
/ \
...
/ \
*14.27.32.0/23 14.27.34.0/23
/ \
(null) 14.27.35.0/24*
(14.27.34.0/24)
对于每个剩余的输入范围,您将再次运行树,在必要时将叶节点一分为二,通常会产生更多的叶,但始终会删除部分地址空间
最后,您只需按照方便的顺序遍历生成的树,收集剩余叶子的苹果酒。请注意,在此阶段中,您必须排除以前细分的项目。例如,在上面的树中,如果您下一次处理输入范围<代码> 1427.35.0/ 24 ,您将离开<代码> 1427.34.0/ 23 < /代码>,没有CHI。
public class NetworkRange {
private long startAddress;
private long endAddress;
public NetworkRange(String start, String end) {
startAddress = addressRepresentationToAddress(start);
endAddress = addressRepresentationToAddress(end);
}
public NetworkRange(long start, long end) {
startAddress = start;
endAddress = end;
}
public String getStartAddress() {
return addressToAddressRepresentation(startAddress);
}
public String getEndAddress() {
return addressToAddressRepresentation(endAddress);
}
static String addressToAddressRepresentation(long address) {
String result = String.valueOf(address % 256);
for (int i = 1; i < 4; i++) {
address = address / 256;
result = String.valueOf(address % 256) + "." + result;
}
return result;
}
static long addressRepresentationToAddress(String addressRep) {
long result = 0L;
String[] tokens = addressRep.split("\\.");
for (int i = 0; i < 4; i++) {
result += Math.pow(256, i) * Long.parseLong(tokens[3-i]);
}
return result;
}
public List<NetworkRange> splitByExcludedRange(NetworkRange excludedRange) {
if (this.startAddress == excludedRange.startAddress && this.endAddress == excludedRange.endAddress)
return Arrays.asList();
if (this.startAddress == excludedRange.startAddress)
return Arrays.asList(new NetworkRange(excludedRange.endAddress+1, this.endAddress));
if (this.endAddress == excludedRange.endAddress)
return Arrays.asList(new NetworkRange(this.startAddress, excludedRange.startAddress-1));
return Arrays.asList(new NetworkRange(this.startAddress, excludedRange.startAddress-1),
new NetworkRange(excludedRange.endAddress+1, this.endAddress));
}
public boolean includes(NetworkRange excludedRange) {
return this.startAddress <= excludedRange.startAddress && this.endAddress >= excludedRange.endAddress;
}
public String toString() {
return "[" + getStartAddress() + "-" + getEndAddress() + "]";
}
}
public class RangeProducer {
private NetworkRange global;
public RangeProducer(NetworkRange global) {
this.global = global;
}
public List<NetworkRange> computeEffectiveRanges(List<NetworkRange> excludedRanges) {
List<NetworkRange> effectiveRanges = new ArrayList<>();
effectiveRanges.add(global);
List<NetworkRange> effectiveRangesSplitted = new ArrayList<>();
for (NetworkRange excludedRange : excludedRanges) {
for (NetworkRange effectiveRange : effectiveRanges) {
if (effectiveRange.includes(excludedRange)) {
effectiveRangesSplitted.addAll(effectiveRange.splitByExcludedRange(excludedRange));
} else {
effectiveRangesSplitted.add(effectiveRange);
}
}
effectiveRanges = effectiveRangesSplitted;
effectiveRangesSplitted = new ArrayList<>();
}
return effectiveRanges;
}
}
public static void main(String[] args) {
NetworkRange global = new NetworkRange("10.0.0.0", "10.255.255.255");
NetworkRange ex1 = new NetworkRange("10.0.0.0", "10.0.1.255");
NetworkRange ex2 = new NetworkRange("10.1.0.0", "10.1.1.255");
NetworkRange ex3 = new NetworkRange("10.6.1.0", "10.6.2.255");
List<NetworkRange> excluded = Arrays.asList(ex1, ex2, ex3);
RangeProducer producer = new RangeProducer(global);
for (NetworkRange effective : producer.computeEffectiveRanges(excluded)) {
System.out.println(effective);
}
}
[10.0.2.0-10.0.255.255]
[10.1.2.0-10.6.0.255]
[10.6.3.0-10.255.255.255]