java - 检查 IP 地址是否在多个可能的子网中

标签 java networking network-programming ip

我正在解析 Apache 日志并想检查 IP 地址是否属于约 300 个可能的子网列表 ( https://github.com/client9/ipcat)。

  • Internet 流量有很多不同的 IP(我不知道它们属于哪个子网)。
  • 我正在使用 Apache Commons SubnetUtils 包来存储子网。
  • 将 300 个子网中所有可能的 IP 存储在 HashMap 中会占用太多内存。
  • 遍历每个 IP 的每个 SubnetUtil(即使使用之前查找的 HashMap 缓存)非常慢。

还有什么我可以在这里做的吗?

最佳答案

您可以构建一个带有子网的树结构 - 它可以一点一点地构建。这会将检查次数从 300 次减少到最多 32 次(假设 IPv4),但在大多数情况下要少得多。 (因为它要么在几位之后不匹配,要么在子网掩码的平均长度上匹配)

这是执行此操作的简单二叉树实现。您可能想用一些函数来装饰它,以更常见的 "a.b.c.d/e" 格式解析子网。

public class SubnetTree {
    private SubnetTree one, zero;
    private boolean terminating;

    public void addSubnet(int net, int bits) {
        if (terminating) {
            // If this node is already terminating, then no need to add
            // subnets that are more specific
            return;
        }
        if (bits > 0) {
            boolean bit = ((net >>> 31) & 1) == 1;
            if (bit) {
                if (one == null) {
                    one = new SubnetTree();
                }
                one.addSubnet(net << 1, bits - 1);
            } else {
                if (zero == null) {
                    zero = new SubnetTree();
                }
                zero.addSubnet(net << 1, bits - 1);
            }
        } else {
            terminating = true;
        }
    }

    public boolean isInRange(int address) {
        if (terminating) {
            return true;
        }
        boolean bit = ((address >>> 31) & 1) == 1;
        if (bit) {
            if (one == null) {
                return false;
            } else {
                return one.isInRange(address << 1);
            }
        } else {
            if (zero == null) {
                return false;
            } else {
                return zero.isInRange(address << 1);
            }
        }
    }
}

此代码的一个非常简单的测试:

public static void main(String[] args) {
    SubnetTree tree = new SubnetTree();
    tree.add(Integer.parseUnsignedInt("01100110000000000000000000000000", 2), 8);
    System.out.println("true: " + tree.isInRange(Integer.parseUnsignedInt("01100110000000000000100010000101", 2)));
    System.out.println("false: " + tree.isInRange(Integer.parseUnsignedInt("01101110000000000000100010000101", 2)));

    tree.add(Integer.parseUnsignedInt("01001110000000000000000000000000", 2), 6);
    System.out.println("true: " + tree.isInRange(Integer.parseUnsignedInt("01100110000000000000100010000101", 2)));
    System.out.println("false: " + tree.isInRange(Integer.parseUnsignedInt("01101110000000000000100010000101", 2)));
    System.out.println("true: " + tree.isInRange(Integer.parseUnsignedInt("01001110100000000000000000000000", 2)));
    System.out.println("true: " + tree.isInRange(Integer.parseUnsignedInt("01001100100000000000000000111111", 2)));
}

关于java - 检查 IP 地址是否在多个可能的子网中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38996895/

相关文章:

java - 硬币翻转序列

java - 在 Java 中使用 DOM 通过 XSLT 转换 XML

java - 使用 DiscriminatorColumn 和 'wild' DiscriminatorValue 进行 JPA 实体继承

java - 如何处理忘记密码

security - 如何使用 iptable 阻止来自外部网络的网络流量?

c - 套接字编程 TCP 。服务器编程不断循环

python - 检查远程主机是否在 Python 中启动

c++ - 我可以重复使用 TCP 连接吗?

android - Android 网络库 : OkHTTP, Retrofit 和 Volley 的比较

c++ - IP 地址重叠/在 CIDR 范围内