有没有人知道一个java组件来检查IP地址是否来自特定的网络/网络掩码?

时间:2009-02-23 11:42:07

标签: java networking ip

我需要确定给定的IP地址是否来自某个特殊网络,我必须自动进行身份验证。

7 个答案:

答案 0 :(得分:24)

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有a bug阻止它在某些情况下给出正确的答案。 Carson建议使用SVN版本来避免这个错误。

答案 1 :(得分:16)

选项1:

使用spring-security-web的{​​{3}}。与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的IpAddressMatcher的略微修改版本,因此它对除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);
        }
    }
}

通知:请注意,对于使用此选项,您有责任(而不是我的)仔细检查original class以确保使用此代码您不违反任何上述许可规定的条款。 (当然,我将此代码发布到Stackoverflow.com并不违反。)

答案 2 :(得分:11)

您也可以尝试

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

或更短

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

答案 3 :(得分:1)

The open-source IPAddress Java library将对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

答案 4 :(得分:0)

要检查子网中的IP,我在SubnetUtils类中使用了isInRange方法。但是这种方法有一个错误,如果您的子网是X,每个低于X的IP地址,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;
}

答案 5 :(得分:0)

我知道这是一个非常老的问题,但是当我想解决相同的问题时偶然发现了这个问题。

我相信有一个commons-ip-math库很不错。请注意,截至2019年5月,该库尚未进行任何更新(可能是其已经非常成熟的库)。它在maven-central

上可用

它支持同时使用IPv4和IPv6地址。他们的简要文档提供了有关如何检查IPv4IPv6

的地址是否在特定范围内的示例。

用于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);

答案 6 :(得分:-1)

这是一个适用于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;
    }
}