Mam adresy IP i maskę, taką jak 10.1.1.1/32
. Chciałbym sprawdzić, czy 10.1.1.1
znajduje się w tym zakresie. Czy istnieje biblioteka lub narzędzie, które by to zrobiły, czy muszę napisać coś samemu?Sprawdzanie poprawności adresu IP (z maską)
Odpowiedz
Najpierw będziemy chcieli do konwersji adresów IP do płaskich int
S, który będzie łatwiej pracować:
String s = "10.1.1.99";
Inet4Address a = (Inet4Address) InetAddress.getByName(s);
byte[] b = a.getAddress();
int i = ((b[0] & 0xFF) << 24) |
((b[1] & 0xFF) << 16) |
((b[2] & 0xFF) << 8) |
((b[3] & 0xFF) << 0);
Gdy masz adresy IP jako zwykły int
s można zrobić kilka bitowej arytmetyki aby wykonać sprawdzenie:
int subnet = 0x0A010100; // 10.1.1.0/24
int bits = 24;
int ip = 0x0A010199; // 10.1.1.99
// Create bitmask to clear out irrelevant bits. For 10.1.1.0/24 this is
// 0xFFFFFF00 -- the first 24 bits are 1's, the last 8 are 0's.
//
// -1 == 0xFFFFFFFF
// 32 - bits == 8
// -1 << 8 == 0xFFFFFF00
mask = -1 << (32 - bits)
if ((subnet & mask) == (ip & mask)) {
// IP address is in the subnet.
}
Załóżmy, że zaczynam od 'String ip =" 10.1.1.1 "; int maska = 24' jak uzyskać '0x0A010100'? –
@ nn4l Dzięki, zaktualizowałem moją odpowiedź, aby uwzględnić Twoją poprawkę. –
Więc naprawdę nie ma na to żadnej pomocy w bibliotece klasy podstawowej lub w jakimś zalecanym pakiecie obsługi sieci trzeciej strony? – binki
Dzięki Johnowi Kugelmanowi użyłem jego fragmentów kodu do stworzenia tej klasy.
package bs;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* Represents an IP range based on an address/mask.
* @author Scott Plante, using code snippets by John Kugelman.
*/
public class IPMask
{
public static void main(String args[])
throws UnknownHostException
{
IPMask ipmask;
ipmask = IPMask.getIPMask("192.168.20.32/24");
System.out.println("Checking "+ipmask+"...");
test(ipmask, "192.168.20.31 ", true);
test(ipmask, "192.168.20.32 ", true);
test(ipmask, "192.168.20.33 ", true);
test(ipmask, "192.168.20.34 ", true);
test(ipmask, "192.168.20.35 ", true);
test(ipmask, "192.168.20.36 ", true);
test(ipmask, "192.168.20.254", true);
test(ipmask, "192.168.20.157", true);
test(ipmask, "192.168.21.1 ", false);
test(ipmask, "192.168.19.255", false);
test(ipmask, "192.168.24.1 ", false);
ipmask = IPMask.getIPMask("192.168.20.32/31");
System.out.println("Checking "+ipmask+"...");
test(ipmask, "192.168.20.31 ", false);
test(ipmask, "192.168.20.32 ", true);
test(ipmask, "192.168.20.33 ", true);
test(ipmask, "192.168.20.34 ", false);
test(ipmask, "192.168.20.35 ", false);
test(ipmask, "192.168.20.36 ", false);
test(ipmask, "192.168.20.254", false);
test(ipmask, "192.168.20.157", false);
test(ipmask, "192.168.21.1 ", false);
test(ipmask, "192.168.19.255", false);
test(ipmask, "192.168.24.1 ", false);
ipmask = IPMask.getIPMask("192.168.20.32/23");
System.out.println("Checking "+ipmask+"...");
test(ipmask, "192.168.20.31 ", true);
test(ipmask, "192.168.20.32 ", true);
test(ipmask, "192.168.20.33 ", true);
test(ipmask, "192.168.20.254", true);
test(ipmask, "192.168.21.254", true);
test(ipmask, "192.168.19.255", false);
test(ipmask, "192.168.24.1 ", false);
}
public static void test(IPMask ipmask, String addr, boolean expect)
throws UnknownHostException
{
boolean got = ipmask.matches(addr);
System.out.println(addr + "\t(" + expect + ") ?\t"+got
+ "\t" + (got==expect?"":"!!!!!!!!"));
}
private Inet4Address i4addr;
private byte maskCtr;
private int addrInt;
private int maskInt;
public IPMask(Inet4Address i4addr, byte mask)
{
this.i4addr = i4addr;
this.maskCtr = mask;
this.addrInt = addrToInt(i4addr);
this.maskInt = ~((1 << (32 - maskCtr)) - 1);
}
/** IPMask factory method.
*
* @param addrSlashMask IP/Mask String in format "nnn.nnn.nnn.nnn/mask". If
* the "/mask" is omitted, "/32" (just the single address) is assumed.
* @return a new IPMask
* @throws UnknownHostException if address part cannot be parsed by
* InetAddress
*/
public static IPMask getIPMask(String addrSlashMask)
throws UnknownHostException
{
int pos = addrSlashMask.indexOf('/');
String addr;
byte maskCtr;
if (pos==-1)
{
addr = addrSlashMask;
maskCtr = 32;
}
else
{
addr = addrSlashMask.substring(0, pos);
maskCtr = Byte.parseByte(addrSlashMask.substring(pos + 1));
}
return new IPMask((Inet4Address) InetAddress.getByName(addr), maskCtr);
}
/** Test given IPv4 address against this IPMask object.
*
* @param testAddr address to check.
* @return true if address is in the IP Mask range, false if not.
*/
public boolean matches(Inet4Address testAddr)
{
int testAddrInt = addrToInt(testAddr);
return ((addrInt & maskInt) == (testAddrInt & maskInt));
}
/** Convenience method that converts String host to IPv4 address.
*
* @param addr IP address to match in nnn.nnn.nnn.nnn format or hostname.
* @return true if address is in the IP Mask range, false if not.
* @throws UnknownHostException if the string cannot be decoded.
*/
public boolean matches(String addr)
throws UnknownHostException
{
return matches((Inet4Address)InetAddress.getByName(addr));
}
/** Converts IPv4 address to integer representation.
*/
private static int addrToInt(Inet4Address i4addr)
{
byte[] ba = i4addr.getAddress();
return (ba[0] << 24)
| ((ba[1]&0xFF) << 16)
| ((ba[2]&0xFF) << 8)
| (ba[3]&0xFF);
}
@Override
public String toString()
{
return "IPMask(" + i4addr.getHostAddress() + "/" + maskCtr + ")";
}
@Override
public boolean equals(Object obj)
{
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final IPMask that = (IPMask) obj;
return (this.addrInt == that.addrInt && this.maskInt == that.maskInt);
}
@Override
public int hashCode()
{
return this.maskInt + this.addrInt;
}
}
ja musiałem dodać maskę do int konwersji w jego kodzie:
Inet4Address a = (Inet4Address) InetAddress.getByName("192.192.192.192");
byte[] b = a.getAddress();
int i = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3] << 0);
System.out.println(Integer.toHexString(i));
System.out.println(Integer.toHexString(addrToInt(a)));
Produkcja:
ffffffc0
c0c0c0c0
Na moim systemie:
$> uname -a
Linux guin 2.6.37.6-0.5-desktop #1 SMP PREEMPT 2011-04-25 21:48:33 +0200 x86_64 x86_64 x86_64 GNU/Linux
$> java -version
java version "1.6.0_25"
Java(TM) SE Runtime Environment (build 1.6.0_25-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.0-b11, mixed mode)
$>
ty może usunąć główne i testowe metody z powyższego c dziewczyna. Są one dostosowane do kodu testu jednostkowego i dodane tutaj dla uproszczenia.
public static boolean netMatch(String addr, String addr1){ //addr is subnet address and addr1 is ip address. Function will return true, if addr1 is within addr(subnet)
String[] parts = addr.split("/");
String ip = parts[0];
int prefix;
if (parts.length < 2) {
prefix = 0;
} else {
prefix = Integer.parseInt(parts[1]);
}
Inet4Address a =null;
Inet4Address a1 =null;
try {
a = (Inet4Address) InetAddress.getByName(ip);
a1 = (Inet4Address) InetAddress.getByName(addr1);
} catch (UnknownHostException e){}
byte[] b = a.getAddress();
int ipInt = ((b[0] & 0xFF) << 24) |
((b[1] & 0xFF) << 16) |
((b[2] & 0xFF) << 8) |
((b[3] & 0xFF) << 0);
byte[] b1 = a1.getAddress();
int ipInt1 = ((b1[0] & 0xFF) << 24) |
((b1[1] & 0xFF) << 16) |
((b1[2] & 0xFF) << 8) |
((b1[3] & 0xFF) << 0);
int mask = ~((1 << (32 - prefix)) - 1);
if ((ipInt & mask) == (ipInt1 & mask)) {
return true;
}
else {
return false;
}
}
Oto wersja, która odbywa się w kilku podsieci opisy typowych sposobów, w tym IPv6.
Na podstawie innego opublikowanego tutaj kodu. Na adresach IPv4 adresy mogą działać wolniej niż podejście do wykonywania operacji binarnych na gołym int
.
package de.c3oe.tryanderror;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @author c3oe.de, based on snippets from Scott Plante, John Kugelmann
*/
public class Subnet
{
final private int bytesSubnetCount;
final private BigInteger bigMask;
final private BigInteger bigSubnetMasked;
/** For use via format "192.168.0.0/24" or "2001:db8:85a3:880:0:0:0:0/57" */
public Subnet(final InetAddress subnetAddress, final int bits)
{
this.bytesSubnetCount = subnetAddress.getAddress().length; // 4 or 16
this.bigMask = BigInteger.valueOf(-1).shiftLeft(this.bytesSubnetCount*8 - bits); // mask = -1 << 32 - bits
this.bigSubnetMasked = new BigInteger(subnetAddress.getAddress()).and(this.bigMask);
}
/** For use via format "192.168.0.0/255.255.255.0" or single address */
public Subnet(final InetAddress subnetAddress, final InetAddress mask)
{
this.bytesSubnetCount = subnetAddress.getAddress().length;
this.bigMask = null == mask ? BigInteger.valueOf(-1) : new BigInteger(mask.getAddress()); // no mask given case is handled here.
this.bigSubnetMasked = new BigInteger(subnetAddress.getAddress()).and(this.bigMask);
}
/**
* Subnet factory method.
* @param subnetMask format: "192.168.0.0/24" or "192.168.0.0/255.255.255.0"
* or single address or "2001:db8:85a3:880:0:0:0:0/57"
* @return a new instance
* @throws UnknownHostException thrown if unsupported subnet mask.
*/
public static Subnet createInstance(final String subnetMask)
throws UnknownHostException
{
final String[] stringArr = subnetMask.split("/");
if (2 > stringArr.length)
return new Subnet(InetAddress.getByName(stringArr[ 0 ]), (InetAddress)null);
else if (stringArr[ 1 ].contains(".") || stringArr[ 1 ].contains(":"))
return new Subnet(InetAddress.getByName(stringArr[ 0 ]), InetAddress.getByName(stringArr[ 1 ]));
else
return new Subnet(InetAddress.getByName(stringArr[ 0 ]), Integer.parseInt(stringArr[ 1 ]));
}
public boolean isInNet(final InetAddress address)
{
final byte[] bytesAddress = address.getAddress();
if (this.bytesSubnetCount != bytesAddress.length)
return false;
final BigInteger bigAddress = new BigInteger(bytesAddress);
return bigAddress.and(this.bigMask).equals(this.bigSubnetMasked);
}
@Override
final public boolean equals(Object obj)
{
if (! (obj instanceof Subnet))
return false;
final Subnet other = (Subnet)obj;
return this.bigSubnetMasked.equals(other.bigSubnetMasked) &&
this.bigMask.equals(other.bigMask) &&
this.bytesSubnetCount == other.bytesSubnetCount;
}
@Override
final public int hashCode()
{
return this.bytesSubnetCount;
}
@Override
public String toString()
{
final StringBuilder buf = new StringBuilder();
bigInteger2IpString(buf, this.bigSubnetMasked, this.bytesSubnetCount);
buf.append('/');
bigInteger2IpString(buf, this.bigMask, this.bytesSubnetCount);
return buf.toString();
}
static private void bigInteger2IpString(final StringBuilder buf, final BigInteger bigInteger, final int displayBytes)
{
final boolean isIPv4 = 4 == displayBytes;
byte[] bytes = bigInteger.toByteArray();
int diffLen = displayBytes - bytes.length;
final byte fillByte = 0 > (int)bytes[ 0 ] ? (byte)0xFF : (byte)0x00;
int integer;
for (int i = 0; i < displayBytes; i++)
{
if (0 < i && ! isIPv4 && i % 2 == 0)
buf.append(':');
else if (0 < i && isIPv4)
buf.append('.');
integer = 0xFF & (i < diffLen ? fillByte : bytes[ i - diffLen ]);
if (! isIPv4 && 0x10 > integer)
buf.append('0');
buf.append(isIPv4 ? integer : Integer.toHexString(integer));
}
}
}
możliwe duplikat [Czy ktoś wie komponent Java, aby sprawdzić, czy adres IP jest od określonej sieci/maska sieci?] (Http://stackoverflow.com/questions/577363/does-anyone-know-a- java-component-to-check-if-ip-address-is-from-specific-netwo) –