今のJavaプログラマのほとんどがビット演算のコードを書くことはしないだろう。
サブネットマスクより、IPアドレスの妥当性を検査するためのユーティリティクラスを書いてみた。
import java.math.BigInteger;
public final class NetAddressUtil{
private NetAddressUtil(){}
/**
* サブネットマスク検査.
* 検査したいIPアドレス、セグメントIPアドレス、マスク長を指定して、
* サブネットマスクしたIPアドレスの範囲であるかを検査する。
* @param ipaddr 検査したいIPアドレス文字列、"xxx.xxx.xxx.xxx" 形式
* @param segaddr セグメントIPアドレス、"xxx.xxx.xxx.xxx" 形式
* @param len マスク長、1~32
* @return true=OK,false=NG
*/
public static boolean isScorp(String ipaddr,String segaddr,int len){
byte bmask = getMask(len);
byte bseg = addrTobyte(segaddr);
BigInteger minBigInt = new BigInteger(byteAND(bseg,bmask));
byte bmax = byteOR(bseg,byteXOR(bmask,addrTobyte("255.255.255.255")));
BigInteger maxBigInt = new BigInteger(bmax);
BigInteger bchk = new BigInteger(addrTobyte(ipaddr));
return minBigInt.compareTo(bchk) <= 0 && bchk.compareTo(maxBigInt) <= 0 ? true : false;
}
/**
* サブネットマスクした値の最小アドレスを返す。
* (例)
* 192.168.87.22 とマスク長 24 を指定した場合、192.168.87.0 を byte で返す
* @param segaddr IPアドレス"xxx.xxx.xxx.xxx" 形式
* @param len マスク長、1~32
* @return 最小アドレスbyte
*/
public static byte minSegment(String segaddr,int len){
byte bmask = getMask(len);
byte bseg = addrTobyte(segaddr);
byte bw = byteAND(bseg,bmask);
if (bw[0]==0 && bw[1]==0 && bw[2]==0 && bw[3]==0){
byte b = {0,0,0,0};
byte br = new byte[4];
int p = b.length > 4 ? 1 : 0;
for(int i=0;i < br.length;i++,p++){
br[i] = b[p];
}
return br;
}
byte b = new BigInteger(1,bw).toByteArray();
byte br = new byte[4];
int p = b.length > 4 ? 1 : 0;
for(int i=0;i < br.length;i++,p++){
br[i] = b[p];
}
return br;
}
/**
* サブネットマスクした値の最大アドレスを返す。
* (例)
* 192.168.87.22 とマスク長 24 を指定した場合、192.168.87.255 を byte で返す
* @param segaddr IPアドレス"xxx.xxx.xxx.xxx" 形式
* @param len マスク長、1~32
* @return 最大アドレスbyte
*/
public static byte maxSegment(String segaddr,int len){
byte bmask = getMask(len);
byte bseg = addrTobyte(segaddr);
byte bmax = byteOR(bseg,byteXOR(bmask,addrTobyte("255.255.255.255")));
byte b = new BigInteger(1,bmax).toByteArray();
byte br = new byte[4];
int p = b.length > 4 ? 1 : 0;
for(int i=0;i < br.length;i++,p++){
br[i] = b[p];
}
return br;
}
/**
* マスク値で、有効アドレス数を求める
* @param len len マスク長、1~32
* @return 有効アドレス数
*/
public static long countSegment(int len){
byte bmask = getMask(len);
byte bseg = new byte{-1,-1,-1,-1};
byte bx = new BigInteger(1
,byteOR(bseg,byteXOR(bmask,addrTobyte("255.255.255.255"))))
.toByteArray();
byte bw = byteAND(bseg,bmask);
if (bw[0]==0 && bw[1]==0 && bw[2]==0 && bw[3]==0){
byte b = {0,0,0,0};
byte br = new byte[4];
int p = b.length > 4 ? 1 : 0;
for(int i=0;i < br.length;i++,p++){
br[i] = b[p];
}
byte bmax = new byte[4];
byte bmin = new byte[4];
int k = bx.length > 4 ? 1 : 0;
for(int i=0;i < bmax.length;i++,k++){
bmax[i] = bx[k];
bmin[i] = br[k];
}
BigInteger bigintMax = new BigInteger(1,bmax);
BigInteger bigintMin = new BigInteger(1,bmin);
return bigintMax.longValue() - bigintMin.longValue() + 1;
}
byte bn = new BigInteger(1,bw).toByteArray();
byte bmax = new byte[4];
byte bmin = new byte[4];
int p = bx.length > 4 ? 1 : 0;
for(int i=0;i < bmax.length;i++,p++){
bmax[i] = bx[p];
bmin[i] = bn[p];
}
BigInteger bigintMax = new BigInteger(1,bmax);
BigInteger bigintMin = new BigInteger(1,bmin);
return bigintMax.longValue() - bigintMin.longValue() + 1;
}
/**
* IPアドレス文字列、"xxx.xxx.xxx.xxx" → byte.
* @param s IPアドレス文字列
* @return byte
*/
public static byte addrTobyte(String s){
String sp = s.split("\\.");
byte b = new byte[4];
for(int i=0;i < 4;i++){
b[i] = (byte)(Integer.parseInt(sp[i]));
}
return b;
}
/**
* マスク長→サブネットマスク byte
* @param n マスク長
* @return サブネットマスク byte
*/
public static byte getMask(int n){
byte b = new BigInteger(1,new byte{-1,-1,-1,-1})
.shiftRight(n)
.xor(new BigInteger(1,new byte{-1,-1,-1,-1}))
.toByteArray();
byte br = new byte[4];
for(int i=0;i < br.length;i++){
br[i] = b[i+1];
}
return br;
}
static byte byteAND(byte b1,byte b2){
byte r = new byte[b1.length];
for(int i=0;i < r.length;i++){
r[i] = (byte)(b1[i] & b2[i]);
}
return r;
}
static byte byteOR(byte b1,byte b2){
byte r = new byte[b1.length];
for(int i=0;i < r.length;i++){
r[i] = (byte)(b1[i] | b2[i]);
}
return r;
}
static byte byteXOR(byte b1,byte b2){
byte[] r = new byte[b1.length];
for(int i=0;i < r.length;i++){
r[i] = (byte)(b1[i] ^ b2[i]);
}
return r;
}
}