/*
* Copyright 2002-2019 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;
/**
* 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 JRE.
*/
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);
assert (requiredAddress.getAddress().length * 8 >= nMaskBits) :
String.format("IP address %s is too short for bitmask of length %d",
ipAddress, nMaskBits);
}
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 nMaskFullBytes = nMaskBits / 8;
byte finalByte = (byte) (0xFF00 >> (nMaskBits & 0x07));
// System.out.println("Mask is " + new sun.misc.HexDumpEncoder().encode(mask));
for (int i = 0; i < nMaskFullBytes; i++) {
if (remAddr[i] != reqAddr[i]) {
return false;
}
}
if (finalByte != 0) {
return (remAddr[nMaskFullBytes] & finalByte) == (reqAddr[nMaskFullBytes] & finalByte);
}
return true;
}
private InetAddress parseAddress(String address) {
try {
return InetAddress.getByName(address);
}
catch (UnknownHostException e) {
throw new IllegalArgumentException("Failed to parse address" + address, e);
}
}
}
/**
* 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;
}
}
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);
/**
* Test is the testAddressRaw is within the networkAddressRaw by specifying networkPrefixLength.
*/
public static boolean testLocal(byte [] networkAddressRaw, int networkPrefixLength, byte [] testAddressRaw)
{
// If the addresses are of different length
if (networkAddressRaw.length != testAddressRaw.length) {
return false;
}
BitSet testAddrBits = BitSet.valueOf(testAddressRaw);
BitSet subnetAddrBits = BitSet.valueOf(networkAddressRaw);
// compare the addresses, mutates testAddrBits
testAddrBits.xor(subnetAddrBits);
// Keep 1s in the network part of the address only
// discard any 1s in the host (after the network) part of the address
// This would be equivalent to (testAddrBits & networkMaskBits)
testAddrBits.clear(networkPrefixLength, networkAddressRaw.length * 8);
// If any 1s remain then the network parts of the addresses were not the same
return testAddrBits.cardinality() == 0;
}
/**
* Test is the testAddressRaw is within the networkAddressRaw by specifying network mask with networkMaskRaw.
*/
public static boolean testLocal(byte [] networkAddressRaw, byte [] networkMaskRaw, byte [] testAddressRaw)
{
if (networkAddressRaw.length != networkMaskRaw.length) {
throw new IllegalArgumentException("Network mask length must be same as network address length");
}
// If the addresses are of different length
if (networkAddressRaw.length != testAddressRaw.length) {
return false;
}
BitSet testAddrBits = BitSet.valueOf(testAddressRaw);
BitSet subnetAddrBits = BitSet.valueOf(networkAddressRaw);
BitSet networkMaskBits = BitSet.valueOf(networkMaskRaw);
// compare the addresses, mutates testAddrBits
testAddrBits.xor(subnetAddrBits);
// Keep 1s in the network part of the address only
// discard any 1s in the host (after the network) part of the address
testAddrBits.and(networkMaskBits);
// If any 1s remain then the network parts of the addresses were not the same
return testAddrBits.cardinality() == 0;
}
这里只介绍了几个方便的方法来处理InetAddress对象或String对象。
// convenience method to work with InetAddress objects directly
public static boolean testLocal(InetAddress networkAddress, InetAddress networkMask, InetAddress testAddress)
throws UnknownHostException
{
return testLocal(
networkAddress.getAddress(),
networkMask.getAddress(),
testAddress.getAddress());
}
// convenience method to work with InetAddress objects directly
public static boolean testLocal(InetAddress networkAddress, int networkPrefixLength, InetAddress testAddress)
{
return testLocal(
networkAddress.getAddress(),
networkPrefixLength,
testAddress.getAddress());
}
// convenience method to work with Strings
public static boolean testLocal(String networkAddress, String networkMask, String testAddress)
throws UnknownHostException
{
return testLocal(
InetAddress.getByName(networkAddress).getAddress(),
InetAddress.getByName(networkMask).getAddress(),
InetAddress.getByName(testAddress).getAddress());
}
// convenience method to work with Strings for addresses and a known network prefix length
public static boolean testLocal(String networkAddress, int networkPrefixLength, String testAddress)
throws UnknownHostException
{
return testLocal(
InetAddress.getByName(networkAddress).getAddress(),
networkPrefixLength,
InetAddress.getByName(testAddress).getAddress());
}
8条答案
按热度按时间6tqwzwtp1#
选项1:
使用
spring-security-web
的IpAddressMatcher,与Apache Commons Net不同,它同时支持ipv4和ipv6。选项2(轻量级解决方案!):
spring-security-web
。如果您不想在项目中包含Spring框架,可以使用此类,它是Spring中original class得一个稍微修改过得版本,因此它没有非JRE依赖项.
注意:注意,使用此选项时,您有责任仔细检查license,以确保使用此代码没有违反上述许可证所规定得任何条款.(当然,我将此代码发布到Stackoverflow.com并不违法.)
voase2hg2#
Apache Commons Net具有
org.apache.commons.net.util.SubnetUtils
,似乎可以满足您的需求。看起来您执行了以下操作:注意,正如carson指出的,Apache Commons Net有a bug,它在某些情况下会阻止它给出正确的答案。卡森建议使用SVN版本来避免这个bug。
ubof19bj3#
你也可以试试
或更短
tcbh2hod4#
The open-source IPAddress Java library将以多态方式为IPv4和IPv6执行此操作,并处理子网。免责声明:我是那个图书馆的项目经理。
示例代码:
输出量:
gcmastyq5#
下面是一个适用于IPv4和IPv6的版本,一个带有前缀,一个带有网络掩码。
d5vmydt96#
我知道这是一个很老的问题,但我偶然发现这个当我正在寻找解决同样的问题。
有一个commons-ip-math库,我相信它做得非常好。请注意,截至2019年5月,该库还没有任何更新(可能是它已经非常成熟的库)。它在maven-central上可用
它支持使用IPv4和IPv6地址。其简要文档中有一些示例,说明如何检查地址是否在IPv4和IPv6的特定范围内
IPv4范围检查示例:
erhoui1w7#
如果你不需要解析花哨的字符串,也就是说你已经有了InetAddress对象,或者你有了可以输入到
InetAddress.getByName()
的普通字符串值形式的地址,那么Java标准库就可以完成这项工作。这在很大程度上与Peter Lawrey的答案中的逻辑相同,只是扩展到支持IPv6。这里有两个非常简短的方法可供选择,具体取决于您是否知道网络前缀长度或掩码。
这里只介绍了几个方便的方法来处理InetAddress对象或String对象。
最后一个main来显示这些方法的优点。这个main()方法可能需要相当新的Java版本。上面的方法应该可以在非常旧的Java版本中工作。
mm5n2pyu8#
为了检查子网中的IP地址,我在SubnetUtils类中使用了isInRange方法。但是这个方法有一个bug,如果你的子网是X,每个低于X的IP地址,isInRange都返回true。例如,如果你的子网是10.10.30.0/24,而你想检查10.10.20.5,这个方法返回true。为了处理这个bug,我使用了下面的代码。