Кто-нибудь знает Java-компонент для проверки, если IP-адрес из определенной сети / маска сети? - PullRequest
22 голосов
/ 23 февраля 2009

Мне нужно определить, принадлежит ли данный IP-адрес какой-либо специальной сети, я должен автоматически проходить аутентификацию.

Ответы [ 7 ]

24 голосов
/ 23 февраля 2009

Apache Commons Net имеет org.apache.commons.net.util.SubnetUtils, который удовлетворяет вашим потребностям. Похоже, вы делаете что-то вроде этого:

SubnetInfo subnet = (new SubnetUtils("10.10.10.0", "255.255.255.128")).getInfo();
boolean test = subnet.isInRange("10.10.10.10");

Обратите внимание: carson указывает на то, что в Apache Commons Net имеется ошибка , которая в некоторых случаях не дает правильного ответа. Карсон предлагает использовать версию SVN, чтобы избежать этой ошибки.

16 голосов
/ 05 января 2017

Вариант 1:

Используйте spring-security-web s IpAddressMatcher . В отличие от Apache Commons Net, он поддерживает ipv4 и ipv6.

import org.springframework.security.web.util.matcher.IpAddressMatcher;
...

private void checkIpMatch() {
    matches("192.168.2.1", "192.168.2.1"); // true
    matches("192.168.2.1", "192.168.2.0/32"); // false
    matches("192.168.2.5", "192.168.2.0/24"); // true
    matches("92.168.2.1", "fe80:0:0:0:0:0:c0a8:1/120"); // false
    matches("fe80:0:0:0:0:0:c0a8:11", "fe80:0:0:0:0:0:c0a8:1/120"); // true
    matches("fe80:0:0:0:0:0:c0a8:11", "fe80:0:0:0:0:0:c0a8:1/128"); // false
    matches("fe80:0:0:0:0:0:c0a8:11", "192.168.2.0/32"); // false
}

private boolean matches(String ip, String subnet) {
    IpAddressMatcher ipAddressMatcher = new IpAddressMatcher(subnet);
    return ipAddressMatcher.matches(ip);
}

Вариант 2 (облегченное решение!):

Код в предыдущей части прекрасно работает , но для его включения необходимо spring-security-web. Если вы не желаете включать среду Spring в свой проект, вы можете использовать этот класс, который является слегка измененной версией исходного класса от Spring, так что он имеет нулевую зависимость от любых платформ, кроме JDK. .

/*
 * Copyright 2002-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;

/**
 * Matches a request based on IP Address or subnet mask matching against the remote
 * address.
 * <p>
 * Both IPv6 and IPv4 addresses are supported, but a matcher which is configured with an
 * IPv4 address will never match a request which returns an IPv6 address, and vice-versa.
 *
 * @author Luke Taylor
 * @since 3.0.2
 * 
 * slightly modified by omidzk to have zero dependency to any frameworks other than the JDK.  
 */
public final class IpAddressMatcher {
    private final int nMaskBits;
    private final InetAddress requiredAddress;

    /**
     * Takes a specific IP address or a range specified using the IP/Netmask (e.g.
     * 192.168.1.0/24 or 202.24.0.0/14).
     *
     * @param ipAddress the address or range of addresses from which the request must
     * come.
     */
    public IpAddressMatcher(String ipAddress) {

        if (ipAddress.indexOf('/') > 0) {
            String[] addressAndMask = ipAddress.split("/");
            ipAddress = addressAndMask[0];
            nMaskBits = Integer.parseInt(addressAndMask[1]);
        }
        else {
            nMaskBits = -1;
        }
        requiredAddress = parseAddress(ipAddress);
    }

    public boolean matches(String address) {
        InetAddress remoteAddress = parseAddress(address);

        if (!requiredAddress.getClass().equals(remoteAddress.getClass())) {
            return false;
        }

        if (nMaskBits < 0) {
            return remoteAddress.equals(requiredAddress);
        }

        byte[] remAddr = remoteAddress.getAddress();
        byte[] reqAddr = requiredAddress.getAddress();

        int oddBits = nMaskBits % 8;
        int nMaskBytes = nMaskBits / 8 + (oddBits == 0 ? 0 : 1);
        byte[] mask = new byte[nMaskBytes];

        Arrays.fill(mask, 0, oddBits == 0 ? mask.length : mask.length - 1, (byte) 0xFF);

        if (oddBits != 0) {
            int finalByte = (1 << oddBits) - 1;
            finalByte <<= 8 - oddBits;
            mask[mask.length - 1] = (byte) finalByte;
        }

        // System.out.println("Mask is " + new sun.misc.HexDumpEncoder().encode(mask));

        for (int i = 0; i < mask.length; i++) {
            if ((remAddr[i] & mask[i]) != (reqAddr[i] & mask[i])) {
                return false;
            }
        }

        return true;
    }

    private InetAddress parseAddress(String address) {
        try {
            return InetAddress.getByName(address);
        }
        catch (UnknownHostException e) {
            throw new IllegalArgumentException("Failed to parse address" + address, e);
        }
    }
}

УВЕДОМЛЕНИЕ : обратите внимание, что для использования этой опции вы несете ответственность (а не моя) за тщательное изучение лицензии , чтобы убедиться, что с помощью этого кода вы не нарушаете любые условия, предусмотренные вышеупомянутой лицензией. (Конечно, публикация этого кода на Stackoverflow.com мной не является нарушением.)

11 голосов
/ 23 февраля 2009

Вы также можете попробовать

boolean inSubnet = (ip & netmask) == (subnet & netmask);

или короче

boolean inSubnet = (ip ^ subnet) & netmask == 0;
1 голос
/ 08 января 2019

Библиотека Java с открытым исходным кодом IPAddress будет делать это полиморфно для IPv4 и IPv6 и обрабатывать подсети. Отказ от ответственности: я руководитель проекта этой библиотеки.

Пример кода:

contains("10.10.20.0/30", "10.10.20.3");
contains("10.10.20.0/30", "10.10.20.5");
contains("1::/64", "1::1");
contains("1::/64", "2::1");
contains("1::3-4:5-6", "1::4:5");       
contains("1-2::/64", "2::");
contains("bla", "foo");

static void contains(String network, String address) {
    IPAddressString one = new IPAddressString(network);
    IPAddressString two = new IPAddressString(address);
    System.out.println(one +  " contains " + two + " " + one.contains(two));
}

Выход:

10.10.20.0/30 contains 10.10.20.3 true
10.10.20.0/30 contains 10.10.20.5 false
1::/64 contains 1::1 true
1::/64 contains 2::1 false
1::3-4:5-6 contains 1::4:5 true
1-2::/64 contains 2:: true
bla contains foo false
0 голосов
/ 01 мая 2019

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

Существует библиотека commons-ip-math , которая, я считаю, отлично справляется со своей задачей. Обратите внимание, что по состоянию на май 2019 года в библиотеке не было никаких обновлений (возможно, это уже очень зрелая библиотека). Доступно на Maven-Central

Поддерживается работа с адресами IPv4 и IPv6. Их краткая документация содержит примеры того, как вы можете проверить, находится ли адрес в определенном диапазоне для IPv4 и IPv6

Пример проверки диапазона IPv4:

        String input1 = "192.168.1.0";
        Ipv4 ipv41 = Ipv4.parse(input1);

        // Using CIDR notation to specify the networkID and netmask
        Ipv4Range range = Ipv4Range.parse("192.168.0.0/24");
        boolean result = range.contains(ipv41);
        System.out.println(result); //false

        String input2 = "192.168.0.251";
        Ipv4 ipv42 = Ipv4.parse(input2);

        // Specifying the range with a start and end.
        Ipv4 start = Ipv4.of("192.168.0.0");
        Ipv4 end = Ipv4.of("192.168.0.255");
        range = Ipv4Range.from(start).to(end);

        result = range.contains(ipv42); //true
        System.out.println(result);
0 голосов
/ 04 февраля 2019

- это версия, которая работает с IPv4 и IPv6, одна с префиксом, а другая с маской сети.

/**
 * Check if IP is within an Subnet defined by Network Address and Network Mask
 * @param  ip
 * @param  net
 * @param  mask
 * @return
 */
public static final boolean isIpInSubnet(final String ip, final String net, final int prefix) {
    try {
        final byte[] ipBin   = java.net.InetAddress.getByName(ip  ).getAddress();
        final byte[] netBin  = java.net.InetAddress.getByName(net ).getAddress();
        if(ipBin.length  != netBin.length ) return false;
        int p = prefix;
        int i = 0;
        while(p>=8) { if(ipBin[i] != netBin[i] ) return false; ++i; p-=8; }
        final int m = (65280 >> p) & 255;
        if((ipBin[i] & m) != (netBin[i]&m) ) return false;

        return true;
    } catch(final Throwable t) {
        return false;
    }
}

/**
 * Check if IP is within an Subnet defined by Network Address and Network Mask
 * @param  ip
 * @param  net
 * @param  mask
 * @return
 */
public static final boolean isIpInSubnet(final String ip, final String net, final String mask) {
    try {
        final byte[] ipBin   = java.net.InetAddress.getByName(ip  ).getAddress();
        final byte[] netBin  = java.net.InetAddress.getByName(net ).getAddress();
        final byte[] maskBin = java.net.InetAddress.getByName(mask).getAddress();
        if(ipBin.length  != netBin.length ) return false;
        if(netBin.length != maskBin.length) return false;
        for(int i = 0; i < ipBin.length; ++i) if((ipBin[i] & maskBin[i]) != (netBin[i] & maskBin[i])) return false;
        return true;
    } catch(final Throwable t) {
        return false;
    }
}
0 голосов
/ 30 августа 2017

Чтобы проверить IP в подсети, я использовал метод isInRange в классе SubnetUtils. Но у этого метода есть ошибка, что если ваша подсеть была X, каждый IP-адрес ниже X isInRange возвращает true. Например, если ваша подсеть была 10.10.30.0/24 и вы хотите проверить 10.10.20.5, этот метод возвращает true. Чтобы справиться с этой ошибкой, я использовал следующий код.

public static void main(String[] args){
    String list = "10.10.20.0/24";
    String IP1 = "10.10.20.5";
    String IP2 = "10.10.30.5";
    SubnetUtils  subnet = new SubnetUtils(list);
    SubnetUtils.SubnetInfo subnetInfo = subnet.getInfo();
    if(MyisInRange(subnetInfo , IP1) == true)
       System.out.println("True");
    else 
       System.out.println("False");
    if(MyisInRange(subnetInfo , IP2) == true)
       System.out.println("True");
    else
       System.out.println("False");
}

private boolean MyisInRange(SubnetUtils.SubnetInfo info, String Addr )
{
    int address = info.asInteger( Addr );
    int low = info.asInteger( info.getLowAddress() );
    int high = info.asInteger( info.getHighAddress() );
    return low <= address && address <= high;
}
...