Created
January 29, 2016 09:44
-
-
Save xmedeko/49540c37f33ad29c25b9 to your computer and use it in GitHub Desktop.
IpRange parse and contains test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.xmedeko; | |
import java.net.InetAddress; | |
import java.net.UnknownHostException; | |
import java.util.Arrays; | |
import java.util.logging.Logger; | |
/** | |
* IP range or just one IP address. The main method {@link #containsAddress(byte[])} tests if the given address is in the range. | |
* | |
* @author xmedeko | |
*/ | |
public class IpRange { | |
private static final Logger LOG = Logger.getLogger(IpRange.class); | |
/** | |
* Rozparsuje retezec a vytvori z nej rozsah IP adres. | |
* | |
* @param target | |
* Cil odkazu. | |
* @param strAddress | |
* IP adresa nebo rozsah IP adres tvaru a.b.c.d/mask nebo a.b.c.d - e.f.g.h. | |
* @throws IllegalArgumentException | |
* Pokud {@code atrAddress} je chybny. Chyby se loguji. | |
*/ | |
public static IpRange parse(String strAddress) { | |
byte[] from; | |
byte[] to; | |
try { | |
if (strAddress.indexOf('-') >= 0) { | |
// rozsah adress a.b.c.d - e.f.g.h | |
String[] tokens = strAddress.split("\\s*-\\s*", 3); | |
if (tokens == null || tokens.length != 2) { | |
LOG.error("Wrong #tokens in IP range: " + strAddress); | |
return null; | |
} | |
from = InetAddress.getByName(tokens[0]).getAddress(); | |
to = InetAddress.getByName(tokens[1]).getAddress(); | |
// porovnej adresy pro odhaleni nesrovnalosti | |
int cmp = compareAddresses(from, to); | |
if (cmp == 0) { | |
LOG.warn("IP range is one address: " + strAddress); | |
return new IpRange(from); | |
} else if (cmp > 0) { | |
// opacne poradi | |
LOG.warn("IP range is upside down: " + strAddress); | |
return new IpRange(to, from); | |
} | |
// vse zadano spravne | |
return new IpRange(from, to); | |
} | |
if (strAddress.indexOf('/') >= 0) { | |
// adresa a maska a.b.c.d/mask | |
String[] tokens = strAddress.split("\\s*/\\s*", 2); | |
if (tokens == null || tokens.length != 2) { | |
LOG.error("Wrong #tokens in masked IP range: " + strAddress); | |
return null; | |
} | |
// ziskej adresu | |
from = InetAddress.getByName(tokens[0]).getAddress(); | |
// ziskej masku | |
byte mask = -1; | |
try { | |
mask = Byte.parseByte(tokens[1]); | |
} catch (NumberFormatException e) { | |
LOG.error("Mask is not int: " + mask); | |
return null; | |
} | |
if (mask <= 0 || mask > from.length * 8) { | |
LOG.errorf("Mask is out of limits <0,%d): %d", from.length * 8, mask); | |
return null; | |
} | |
// ziskej adresu aplikuj masku | |
from = InetAddress.getByName(tokens[0]).getAddress(); | |
to = Arrays.copyOf(from, from.length); | |
int n = from.length; // pocet vyte v adrese | |
int first = (mask - 1) / 8; // prvni byte, ktery je ovlivne maskou | |
// projdi vsechny byte az prvniho | |
for (int i = first + 1; i < n; i++) { | |
from[i] = 0; // from nuluj | |
to[i] = (byte) (0xFF); // to nastav na jednicky | |
} | |
// pocet bitu, ktere se maji nastavit ve first-tem bajtu | |
mask = (byte) (mask % 8); | |
if (mask > 0) { | |
// maska jako 11111000, kde pocet jednicek je dan vyrazem mask | |
mask = (byte) (0x80 >> mask - 1); | |
from[first] &= mask; | |
mask ^= 0xFF; // otoceni nul a jednicek | |
to[first] |= mask; | |
} | |
return new IpRange(from, to); | |
} | |
// pouze adresa | |
from = InetAddress.getByName(strAddress).getAddress(); | |
return new IpRange(from); | |
} catch (UnknownHostException e) { | |
LOG.error("Wrong address: " + strAddress); | |
} | |
return null; | |
} | |
/** | |
* Porovna adresy. | |
* | |
* @param addr1 | |
* @param addr2 | |
* @return Nulu, pokus jsou adresy stejne, cislo mensi nez nula, pokud je prvni mensi nez druha, cislo vetsi nez | |
* nula, pokud je prvni vetsi nez druha, | |
*/ | |
private static int compareAddresses(byte[] addr1, byte[] addr2) { | |
// porovnej usek, ktery ma delku minumum z delek | |
int n = Math.min(addr1.length, addr2.length); | |
for (int i = 0; i < n; i++) { | |
// nutny prevod, protoze byte je znamenkovy | |
int a1 = (int)(addr1[i] & 0xFF); | |
int a2 = (int)(addr2[i] & 0xFF); | |
if (a1 < a2) | |
return -1; | |
if (a1 > a2) | |
return 1; | |
} | |
// usek stejny, ale delky se mohou lisit | |
return addr1.length - addr2.length; | |
} | |
/** | |
* Odkud zacina rozsah nebo primo adresa, pokud se nejedna o rozsah ale jen jednu adresu. | |
*/ | |
private byte[] from = null; | |
/** | |
* Kde konci rozsah adress, nebo je null, pokud nejedna o rozsah ale jen jednu adresu. | |
*/ | |
private byte[] to = null; | |
/** | |
* Vytvori rozsah o jedne adrese. | |
* | |
* @param ip | |
* IP adresa. | |
*/ | |
public IpRange(byte[] ip) { | |
this.from = ip; | |
} | |
/** | |
* Vytvori rozsah od IP {@code from} do IP {@code to}. | |
* | |
* @param from | |
* @param to | |
*/ | |
public IpRange(byte[] from, byte[] to) { | |
this.from = from; | |
this.to = to; | |
} | |
/** | |
* @param address | |
* Porovnavana adresa. | |
* @return True, pokud je zadana adresa v tomto rozsahu adres, jinak false. | |
*/ | |
public boolean containsAddress(byte[] address) { | |
if (to == null || to == from) { | |
// neni rozsah, jen jedna adresa | |
return compareAddresses(this.from, address) == 0; | |
} | |
if (compareAddresses(address, from) < 0) // adresa je mensi nez spodni hranice | |
return false; | |
if (compareAddresses(address, to) > 0) // // adresa je vetsi nez spodni hranice | |
return false; | |
// adresa je v rozsahu | |
return true; | |
} | |
/** | |
* Vrati retecez jako {@code description [from - to]}. | |
* | |
* @see java.lang.Object#toString() | |
*/ | |
@Override | |
public String toString() { | |
StringBuilder sb = new StringBuilder(32); | |
// from | |
int i; | |
int n = this.from.length; | |
for (i = 0; i < n; i++) { | |
if (i > 0) | |
sb.append('.'); | |
sb.append((int) from[i] & 0xFF); | |
} | |
if (to != null && to != from) { | |
// to | |
sb.append('-'); | |
n = this.to.length; | |
for (i = 0; i < n; i++) { | |
if (i > 0) | |
sb.append('.'); | |
sb.append((int) to[i] & 0xFF); | |
} | |
} | |
return sb.toString(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment