Согласование ip-адреса с таблицей масок подсети... Каков наилучший подход в Java?

Вот сценарий... У меня есть таблица подсетей. (см. ниже) У меня есть IP-адрес. Я хотел бы узнать, в какой подсети находится ip-адрес, на основе поиска в таблице. Затем эта ассоциация будет использоваться для определения того, в каком месте находится пользователь. Это частное сетевое пространство, поэтому стандартный поиск по местоположению в Интернете не будет применяться. Какой был бы лучший подход? Нужно ли мне разбить ip-адрес на его числовые части и поразрядное сравнение со всеми подсетями.. или есть встроенные инструменты в Java API, которые могли бы облегчить мою жизнь для сравнения IP-адреса с маской подсети?

Я в основном ищу лучший способ сравнить ipaddress с заданной маской подсети и определить да, это совпадение, или нет. Это необязательно. Будут также оценены любые советы о том, как сохранить список и выполнить поиск с минимальными операциями.

В идеале я бы делал что-то похожее на это:

List subnetInfo = null;

subnetInfo = findSubnet('192.168.0.1');  //value null if nothing found

....

//return null if nothing found
List findSubnet(String ipaddress) {
   List subnetDetails = null;
   .... code here ...
   return subnetDetails;
}

Таблица 1: Пример списка подсетей

dk-ballerup-gen-off-v411        10.172.80.0/21  NANR-denmark-ballerup-metallbuen66-ground-first-floors-incl-dhcp-(sr14585203)
ae-dubai-ofssl-gen-off-v410  10.172.88.0/24  NANR-arab-emirates-ofssl-iflex-general-office-v410-(sr12781477)
ru-stpetersburg-gen-off-v411    10.172.89.0/24  NANR-russia-stpetersburg-general-office-incl-dhcp (bsteinba)

Ответ 1

Apache Commons Net имеет SubnetUtils для такого рода вещей, включая определение того, находится ли данный IP-адрес в данной подсети.

Тривиальный пример:

    String[] subnetsMasks = { ... };
    Collection<SubnetInfo> subnets = new ArrayList<SubnetInfo>();
    for (String subnetMask : subnetsMasks) {
        subnets.add(new SubnetUtils(subnetMask).getInfo());
    }

    String ipAddress = ...;
    for (SubnetInfo subnet : subnets) {
        if (subnet.isInRange(ipAddress)) {
            System.out.println("IP Address " + ipAddress + " is in range " + subnet.getCidrSignature());
        }
    }

Ответ 2

Помните, что этот IP-адрес представляет собой только значение int для исторических причин, представленных в виде четырех октетов в десятичной форме.

Для того же токена, подсеть действительно представляет собой диапазон последовательных ints от сетевого адреса до широковещательного адреса.

Поэтому, если ваш объект IP-адреса имеет конвертер int, вы можете просто проверить, находится ли это целое число в пределах подсети, выполнив простые сравнения int.

Ответ 3

Если ваша таблица является таблицей SQL И ваша база данных - PostgreSql, вы можете использовать PostgreSQL types и functions.

Хорошо, что много условий...

Ответ 4

Поверните IP-адрес и сетевую маску в int и AND вместе. Если результат равен IP-адресу, это адрес в этой сетевой маске. Обратите внимание, что вы можете получить более одного соответствия, если ваши сетевые маски не отличаются.

Ответ 6

Я столкнулся с тем же вопросом, что и вы, но ограничился частными сетями (192.168.X.X, 10.x.x.x, ... и IPv6).

Если вы тоже ограничены этим случаем, вы должны использовать встроенный InetAddress.isSiteLocalAddress()

Ответ 7

Я построил на вершине решения скаффмана один метод. Для тех, кто интересуется решением для копирования пасты:

    /**
     * Checks if client ip equals or is in range of ip networks provided by
     * semicolon separated list
     *
     * @param clientIp in numeric form like "192.168.0.10"
     * @param ipList   like "127.0.0.1;192.168.0.0/24;10.0.0.0/8"
     * @return true if client ip from the list os ips and networks
     */
    protected boolean evaluateIp(String clientIp, String ipList) {
        BusinessLogger log = getLog();
        log.debug("Evaluate ip ");
        if (ipList == null) {
            log.info("No ip address provided in ApiPrivilege");
            return false;
        }
        String[] subnetMasks = ipList.split(";");
        for (String subnetMask : subnetMasks) {
            subnetMask = subnetMask.trim();
            if (eq(subnetMask, clientIp))
                return true;
            if (subnetMask.contains("/")) {
                if (new SubnetUtils(subnetMask).getInfo().isInRange(clientIp))
                    return true;
            }
        }
        return false;
    }