IP地址段匹配库2.0

上次实现的IP地址段匹配库,当数据量过大时, 匹配起来实在是太慢了,所以使用算法重新实现了一下。
ip地址段匹配库1.0

IP地址段实体类:

import java.math.BigInteger;
import java.util.Objects;

/**
 * @author chun
 * @date 2023/12/27 15:17
 */
public class IPRanges {
    private BigInteger start;
    private BigInteger end;

    public IPRanges(BigInteger start, BigInteger end) {
        this.start = start;
        this.end = end;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        IPRanges ipRanges = (IPRanges) o;
        return Objects.equals(start, ipRanges.start) && Objects.equals(end, ipRanges.end);
    }

    @Override
    public int hashCode() {
        return Objects.hash(start, end);
    }

    public BigInteger getStart() {
        return start;
    }

    public void setStart(BigInteger start) {
        this.start = start;
    }

    public BigInteger getEnd() {
        return end;
    }

    public void setEnd(BigInteger end) {
        this.end = end;
    }
}

匹配地址匹配工具类

import com.chun.bean.IPRanges;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.util.SubnetUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * @author chun
 * @date 2023/12/27 14:23
 */
@Slf4j
public class IPUtils {
    private static List<IPRanges> ipRanges = new ArrayList<>();

    public static void readIpRangesList(String fullName) throws IOException {
        BufferedReader fileReader = null;
        try {
            File file = new File(fullName);
            fileReader = new BufferedReader(new FileReader(file));
            String line;
            while ((line = fileReader.readLine()) != null) {
                setIpRanges(line);
            }
            buildMatchingArray();
        } finally {
            try {
                fileReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void readIpRangesList(File[] files) throws IOException {
        for (File file : files) {
            BufferedReader fileReader = null;
            try {
                fileReader = new BufferedReader(new FileReader(file));
                String line;
                while ((line = fileReader.readLine()) != null) {
                    setIpRanges(line);
                }
            } finally {
                try {
                    fileReader.close();
                } catch (IOException e) {
                    log.error("", e);
                }
            }
        }
        buildMatchingArray();
    }

    private static void buildMatchingArray() {
        // 对IP地址段进行排序
        ipRanges.sort(Comparator.comparing(IPRanges::getStart).thenComparing(IPRanges::getEnd));

        // 处理重叠的IP地址段
        List<IPRanges> mergedRanges = new ArrayList<>();

        IPRanges currentRange = ipRanges.get(0);
        for (int i = 1; i < ipRanges.size(); i++) {
            IPRanges nextRange = ipRanges.get(i);

            if (currentRange.getEnd().compareTo(nextRange.getStart()) >= 0) { // 当前范围与下一个范围重叠,合并
                if (currentRange.getEnd().compareTo(nextRange.getEnd()) < 0) {
                    currentRange = new IPRanges(currentRange.getStart(), nextRange.getEnd());
                } else {//当前范围包含下一个范围,保留当前

                }
            } else {// 当前范围与下一个范围不重叠,将当前范围添加到结果列表中
                mergedRanges.add(currentRange);
                currentRange = nextRange;
            }
        }

        // 添加最后一个范围
        mergedRanges.add(currentRange);

        ipRanges = mergedRanges;
    }

    public static boolean commonBinarySearch(String ip) {
        BigInteger ip2BigInteger = getIp2BigInteger(ip);
        int low = 0;
        int high = ipRanges.size() - 1;
        int middle = 0;            //定义middle

        //小于第一个的start,大于最后一个的end,就算不在范围内
        if (ip2BigInteger.compareTo(ipRanges.get(low).getStart()) < 0 || ip2BigInteger.compareTo(ipRanges.get(high).getEnd()) > 0 || low > high) {
            return false;
        }

        while (low <= high) {
            middle = (low + high) / 2;
            //先判断是否在中间值的范围内
            BigInteger ipS = ipRanges.get(middle).getStart();
            BigInteger ipE = ipRanges.get(middle).getEnd();
//            if (range[0].equals("112.45.150.66")){
//                System.out.println(111);
//            }
            if (ipExistsInRange(ip2BigInteger, ipS, ipE)) {
                return true;
            }

            if (ipS.compareTo(ip2BigInteger) > 0) {
                //比关键字大则关键字在左区域
                high = middle - 1;
            } else if (ipS.compareTo(ip2BigInteger) < 0) {
                //比关键字小则关键字在右区域
                low = middle + 1;
            } else {//等于
                return true;
            }
        }
        return false;        //最后仍然没有找到,则返回-1
    }

    private static void setIpRanges(String cidrAddress) throws UnknownHostException {
        String startAddress = "";
        String endAddress = "";
        try {
            String[] split = cidrAddress.split("\\/");
            SubnetUtils utils = new SubnetUtils(cidrAddress);
            SubnetUtils.SubnetInfo subnetInfo = utils.getInfo();
            if (split[1].equals("32")) {
                startAddress = split[0];
                endAddress = split[0];
            } else {
                startAddress = subnetInfo.getLowAddress();
                endAddress = subnetInfo.getHighAddress();
            }

            System.out.println("IP CIDR=" + cidrAddress + ",IP范围:[" + startAddress + ", " + endAddress + "]");
        } catch (IllegalArgumentException e) {
            InetAddress networkAddress = InetAddress.getByName(cidrAddress.split("/")[0]);
            int subnetPrefixLength = Integer.parseInt(cidrAddress.split("/")[1]);

            BigInteger start = getStartAddress(networkAddress, subnetPrefixLength);
            BigInteger end = getEndAddress(start, subnetPrefixLength);

            startAddress = getAddressFromBigInteger(start);
            endAddress = getAddressFromBigInteger(end);
            System.out.println("IP CIDR=" + cidrAddress + ",IP范围:[" + startAddress + ", " + endAddress + "]");
        }
        ipRanges.add(new IPRanges(getIp2BigInteger(startAddress), getIp2BigInteger(endAddress)));
    }

    private static String getAddressFromBigInteger(BigInteger address) throws UnknownHostException {
        byte[] bytes = address.toByteArray();
        InetAddress inetAddress;

        if (bytes.length == 16) {
            inetAddress = InetAddress.getByAddress(bytes);
        } else {
            byte[] paddedBytes = new byte[16];
            System.arraycopy(bytes, 0, paddedBytes, 16 - bytes.length, bytes.length);
            inetAddress = InetAddress.getByAddress(paddedBytes);
        }

        return inetAddress.getHostAddress();
    }

    private static BigInteger getStartAddress(InetAddress networkAddress, int subnetPrefixLength) {
        ByteBuffer buffer = ByteBuffer.wrap(networkAddress.getAddress());
        BigInteger start = new BigInteger(1, buffer.array());

        return start.shiftRight(128 - subnetPrefixLength).shiftLeft(128 - subnetPrefixLength);
    }

    private static BigInteger getEndAddress(BigInteger start, int subnetPrefixLength) {
        BigInteger hostCount = BigInteger.ONE.shiftLeft(128 - subnetPrefixLength);
        return start.add(hostCount).subtract(BigInteger.ONE);
    }

    private static boolean ipExistsInRange(BigInteger ip2BigInteger, BigInteger ipS, BigInteger ipE) {
        return ipS.compareTo(ip2BigInteger) <= 0 && ip2BigInteger.compareTo(ipE) <= 0;
    }

    private static long getIp2long(String ip) {
        ip = ip.trim();
        String[] ips = ip.split("\\.");
        long ip2long = 0L;
        for (int i = 0; i < 4; ++i) {
            ip2long = ip2long << 8 | Integer.parseInt(ips[i]);
        }
        return ip2long;
    }

    private static BigInteger getIp2BigInteger(String ip) {
        try {
            InetAddress inetAddress = InetAddress.getByName(ip.trim());

            byte[] bytes = inetAddress.getAddress();
            BigInteger bigInt = new BigInteger(1, bytes);

            return bigInt;
        } catch (UnknownHostException e) {
            // 处理无效的IP地址
            System.out.println("Invalid IP address: " + ip);
            return null; // 或者抛出异常,具体根据需求而定
        }
    }
}

使用方式和1.0一样,使用二分查找重新实现一下,并且支持对传入的IP地址段进行处理,对与IP地址段范围重叠的部分进行聚合去重。

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个网络配置问题,我会尽力回答。首先,我们需要明确一些基本概念: - IP地址:网络上每个设备的唯一标识符。 - 静态路由:手动配置的路由表项,指定了如何将数据包从一个网络传到另一个网络。 - 默认路由:当没有更匹配的路由表项时,数据包将被发送到默认路由所指定的下一跳地址。 现在,我们来看一下如何配置接口IP地址并通过静态路由、默认路由实现全网互通: 1. 配置接口IP地址 首先,需要在每个设备上为接口配置唯一的IP地址。例如,如果我们有两个设备,它们的IP地址分别为192.168.1.1和192.168.1.2,那么我们需要在每个设备上为其接口配置相应的IP地址。 在 Cisco 路由器上,可以使用以下命令配置接口IP地址: ``` interface interface-name ip address ip-address subnet-mask ``` 例如,为 GigabitEthernet0/0 接口配置IP地址的命令如下: ``` Router(config)# interface GigabitEthernet0/0 Router(config-if)# ip address 192.168.1.1 255.255.255.0 ``` 2. 配置静态路由 接下来,需要在每个路由器上配置静态路由,以便路由器知道如何将数据包从一个网络传到另一个网络。例如,如果我们有两个网络,它们的IP地址分别为192.168.1.0/24和192.168.2.0/24,那么我们需要在每个路由器上配置相应的静态路由。 在 Cisco 路由器上,可以使用以下命令配置静态路由: ``` ip route destination-network subnet-mask next-hop-address ``` 例如,为路由器配置将数据包从192.168.1.0/24网络传到192.168.2.0/24网络的静态路由的命令如下: ``` Router(config)# ip route 192.168.2.0 255.255.255.0 192.168.1.2 ``` 其中,destination-network是目标网络的IP地址和子网掩码,next-hop-address是下一跳的IP地址。 3. 配置默认路由 最后,需要在每个路由器上配置默认路由,以便路由器知道当没有更匹配的路由表项时将数据包发送到哪里。例如,我们可以将默认路由配置为下一跳地址为192.168.1.2的路由器。 在 Cisco 路由器上,可以使用以下命令配置默认路由: ``` ip route 0.0.0.0 0.0.0.0 next-hop-address ``` 例如,为路由器配置将数据包发送到下一跳地址为192.168.1.2的默认路由的命令如下: ``` Router(config)# ip route 0.0.0.0 0.0.0.0 192.168.1.2 ``` 现在,我们已经完成了配置接口IP地址并通过静态路由、默认路由实现全网互通的过程。当数据包从一个网络传到另一个网络时,路由器将根据静态路由表或默认路由表将数据包转发到正确的下一跳地址,以实现全网互通。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值