Skip to content

Instantly share code, notes, and snippets.

@xmedeko
Created January 29, 2016 09:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xmedeko/49540c37f33ad29c25b9 to your computer and use it in GitHub Desktop.
Save xmedeko/49540c37f33ad29c25b9 to your computer and use it in GitHub Desktop.
IpRange parse and contains test
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